これは簡単だと思いましたが、予想よりも複雑であることがわかりました。
ディレクトリ内の特定のタイプのすべてのファイルを反復処理したいので、次のように記述します。
#!/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
どのように記述しますか一致するファイルがないものをきれいに処理するループ?
コメント
ls * .zip ; for fname in "${FILES}"...
ただし、for fname in *.zip ; do....
`ls ...`
ではありません。 @cuonglm 'の提案は、パターンが展開されない場合に*.zip
が何も展開されないようにすることです' t任意のファイルに一致します。 ls
引数なしで現在のディレクトリが一覧表示されます。ls
の出力を解析するのが一般的である理由について説明します。回避: ls
を解析しない理由;そのページの上部にあるBashGuide 'の ParsingLs の記事へのリンクも参照してください。回答
bash
で、nullglob
オプションを設定してリテラル文字列として扱われるのではなく、「消える」ものに一致するものはありません。
shopt -s nullglob for fname in *.zip ; do echo "current file is ${fname}" done
POSIXシェルスクリプトでは、fname
が存在します(同時に[ -f ]
である場合は、それが通常のファイル(または通常のファイルへのシンボリックリンク)であり、directory / fifo / deviceなどの他のタイプではないことを確認してください。 。):
for fname in *.zip; do [ -f "$fname" ] || continue printf "%s\n" "current file is $fname" done
[ -f "$fname" ]
を[ -e "$fname" ] || [ -L "$fname ]
に置き換えます。名前が.zip
で終わるすべての(非表示ではない)ファイルをループしたいそれらのタイプ。
名前がivで終わる隠しファイルも検討する場合は、*.zip
を.*.zip .zip *.zip
に置き換えます。 id = “2befeeca63″>
。
コメント
-
shopt -s nullglob
は私はUbuntu17.04を使用していますが、[ -f "$fname" ] || continue
はうまく機能しました。 - @koppor実際には'を使用していないようです。
bash
。 - POSIXソリューションの場合は+1。
回答
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"" {} \;
シェル関数を<でエクスポートする必要がありますこれが機能するためのdivid = "f58dd7dd33">
。これで、find
はシェル関数を実行するbash
を実行し、現在のディレクトリレベルのみに留まります。
コメント
- サブディレクトリを介して繰り返されるもので、一致するものに対して(スクリプトではなく)bash関数を呼び出したい。
- @symcbean I '単一のディレクトリに制限してbash関数を処理するように編集しました
回答
代わりにof:
FILES=`ls *.zip`
試してみてください:
FILES=`ls * | grep *.zip`
この方法でlsが失敗した場合(これはあなたの場合はそうします)失敗した出力をgrepし、空白の変数として返します。
current file is <---Blank Here
これにロジックを追加して、「いいえ」を返すようにすることができます。ファイルが見つかりました “
#!/bin/bash FILES=`ls * | grep *.zip` if [[ $? == "0" ]]; then for fname in "$FILES" ; do echo current file is $fname done else echo "No Files Found" fi
このように、前のコマンドが成功した場合(0の値で終了)、現在のファイルが出力されます。それ以外の場合は、「いいえ見つかったファイル」
コメント
- 私はより良いツール(
find
を使用して問題を修正しようとするのではなく、もう1つのプロセス(grep
)を追加することはお勧めできません。 )または現在のソリューションに関連する設定を変更する(shopt -s nullglob
を使用) - OP 'のコメントによる元の投稿では、
shopt -s nullglob
は機能しません。答えを確認しながらfind
を試しましたが、失敗し続けました。ダニが言った輸出のせいだと思います。
shopt -s nullglob
を追加します。FILES=
を実行すると、このRHEL5ボックス(bash 3.2.25)の空のリストではなく、実行中のスクリプトの名前が返されます。