web-dev-qa-db-ja.com

空の場合を除き、bash反復ファイルリスト

これは簡単だと思いましたが、予想よりも複雑になっています。

ディレクトリ内の特定のタイプのすべてのファイルを反復処理したいので、次のように記述します。

#!/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

一致するファイルを適切に処理しないループを作成するにはどうすればよいですか?

36
symcbean

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に置き換えます。

41
chepner
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 *
2
mikeserv

検索を使用

export -f myshellfunc
find . -mindepth 1 -maxdepth 1 -type f -name '*.Zip' -exec bash -c 'myshellfunc "$0"' {} \;

これを機能させるには、export -fを使用してシェル関数をエクスポートする必要があります。これでfindbashを実行し、シェル関数が実行され、現在のdirレベルのみにとどまります。

2
Dani_l