ディレクトリ(およびサブディレクトリ)内の特定の種類のファイルを一覧表示するシェルスクリプトを記述しようとしています。再帰的な部分で苦労しています。
ここに私が持っているものがあります:
#!/bin/sh
#download dir
DOWNLOADING_DIR=/Users/richard/Downloads
echo "Starting Script..."
for FILE in $DOWNLOADING_DIR/*
do
if [ -d "$FILE" ]
then
echo "...Checking Directory "$FILE
for DFILE in $FILE/*
do
echo "Found file ... $DFILE"
done
else
echo "Found file ... $FILE"
echo ""
fi
done
問題は、ディレクトリが見つかったときに、ディレクトリ内のファイルの名前が見つからないことです。サブディレクトリ内のファイルではなく、サブディレクトリ名のみがリストされます。最初のディレクトリのファイルに対して機能します。
.txtまたは.docファイルを検索して別のディレクトリに移動するには、このスクリプトが必要です。
スクリプトはそれ自身を呼び出さないため、not再帰的です。
以下は、再帰的に持っているようなものを実装するバリエーションです。
_#!/bin/bash
walk_dir () {
shopt -s nullglob dotglob
for pathname in "$1"/*; do
if [ -d "$pathname" ]; then
walk_dir "$pathname"
else
printf '%s\n' "$pathname"
fi
done
}
DOWNLOADING_DIR=/Users/richard/Downloads
walk_dir "$DOWNLOADING_DIR"
_
関数_walk_dir
_は、唯一の引数としてディレクトリパス名を受け取り、その内容を反復処理します。ディレクトリが見つかると、それ自体を再帰的に呼び出して、そのサブディレクトリを走査します。
これを変更して、ファイル名のサフィックスが_.txt
_または_.doc
_であるファイルを検索します。
_#!/bin/bash
walk_dir () {
shopt -s nullglob dotglob
for pathname in "$1"/*; do
if [ -d "$pathname" ]; then
walk_dir "$pathname"
else
case "$pathname" in
*.txt|*.doc)
printf '%s\n' "$pathname"
esac
fi
done
}
DOWNLOADING_DIR=/Users/richard/Downloads
walk_dir "$DOWNLOADING_DIR"
_
上記の「ファイル」とは、ディレクトリまたはディレクトリへのシンボリックリンクではないすべてのものを意味することに注意してください。これは通常のファイルとは異なる場合があります。 dotglob
およびnullglob
シェルオプションをbash
に設定することで、隠しパス名を見つけることができ、空の可能性があるディレクトリを特別にテストする必要がなくなります。
隠された名前を気にしない_/bin/sh
_のバリエーション:
_#!/bin/sh
walk_dir () {
for pathname in "$1"/*; do
if [ -d "$pathname" ]; then
walk_dir "$pathname"
Elif [ -e "$pathname" ]; then
case "$pathname" in
*.txt|*.doc)
printf '%s\n' "$pathname"
esac
fi
done
}
DOWNLOADING_DIR=/Users/richard/Downloads
walk_dir "$DOWNLOADING_DIR"
_
globstar
のexglob
およびbash
シェルオプションを使用すると、ファイルを移動するために次の(再帰なしで)こともできます。
_shopt -s globstar extglob
mv "$DOWNLOADING_DIR"/**/*.@(txt|doc) "$destdir"
_
...結果のファイルリストが長すぎることが判明しない限り。 _**
_は、パス名のスラッシュ全体で一致し(globstar
によって有効化)、*.@(txt|doc)
は、_.txt
_または_.doc
_で終わるファイル名と一致します(有効化によってextglob
)。
_.txt
_または_.doc
_のファイル名サフィックスが付いた通常のファイルを最上位のディレクトリ_$topdir
_の中または下に見つけ、それらを他のディレクトリに移動するはるかに効率的で移植可能な方法_$destdir
_:
_find "$topdir" -type f \( -name '*.txt' -o -name '*.doc' \) \
-exec mv {} "$destdir" \;
_
GNU mv
を使用すると、もう少し効率的にすることができます。
_find "$topdir" -type f \( -name '*.txt' -o -name '*.doc' \) \
-exec mv -t "$destdir" {} +
_
このバリエーションでは、一度に1つのファイルではなくバッチのファイルが移動します。 mv
を_-v
_とともに使用して、何が移動するかを確認するか、_-print
_の前に_-exec
_を追加して、mv
が呼び出されるパス名のリストを取得します。