これは簡単だと思いましたが、予想よりも複雑になっています。
ディレクトリ内の特定のタイプのすべてのファイルを反復処理したいので、次のように記述します。
#!/bin/bash
for fname in *.Zip ; do
echo current file is ${fname}
done
これは動作します少なくとも1つの一致するファイルがある限りディレクトリにあります。ただし、一致するファイルがない場合は、次のようになります。
current file is *.Zip
私はそれから試しました:
#!/bin/bash
FILES=`ls *.Zip`
for fname in "${FILES}" ; do
echo current file is ${fname}
done
ファイルがない場合、ループの本体は実行されませんが、lsからエラーが発生します。
ls: *.Zip: No such file or directory
一致するファイルを適切に処理しないループを作成するにはどうすればよいですか?
bash
では、nullglob
オプションを設定して、何にも一致しないパターンがリテラル文字列として扱われるのではなく、「消える」ようにすることができます。
shopt -s nullglob
for fname in *.Zip ; do
echo "current file is ${fname}"
done
POSIXシェルスクリプトでは、fname
が存在すること(および[ -f ]
と同時に存在すること)を確認し、それが通常のファイル(または通常のファイルへのシンボリックリンク)であり、ディレクトリ/ fifoなどの他のタイプではないことを確認します。 /端末...):
for fname in *.Zip; do
[ -f "$fname" ] || continue
printf '%s\n' "current file is $fname"
done
タイプに関係なく、名前が[ -f "$fname" ]
で終わるすべての(非表示ではない)ファイルをループする場合は、[ -e "$fname" ] || [ -L "$fname ]
を.Zip
に置き換えます。
名前が*.Zip
で終わる隠しファイルも考慮する場合は、.*.Zip .Zip *.Zip
を.Zip
に置き換えます。
set ./* #set the arg array to glob results
${2+":"} [ -e "$1" ] && #if more than one result skip the stat "$1"
printf "current file is %s\n" "$@" #print the whole array at once
###or###
${2+":"} [ -e "$1" ] && #same kind of test
for fname #iterate singly on $fname var for array
do printf "file is %s\n" "$fname" #print each $fname for each iteration
done
ここのコメントでは、関数の呼び出しについて言及しています...
file_fn()
if [ -e "$1" ] || #check if first argument exists
[ -L "$1" ] #or else if it is at least a broken link
then for f #if so iterate on "$f"
do : something w/ "$f"
done
else command <"${1-/dev/null}" #only fail w/ error if at least one arg
fi
file_fn *
検索を使用
export -f myshellfunc
find . -mindepth 1 -maxdepth 1 -type f -name '*.Zip' -exec bash -c 'myshellfunc "$0"' {} \;
これを機能させるには、export -f
を使用してシェル関数をエクスポートする必要があります。これでfind
がbash
を実行し、シェル関数が実行され、現在のdirレベルのみにとどまります。