空の場合を除いて、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 

どのように記述しますか一致するファイルがないものをきれいに処理するループ?

コメント

  • forループを実行する前に、shopt -s nullglobを追加します。
  • @cuolnglm:不気味なことに、FILES=

    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を試しましたが、失敗し続けました。ダニが言った輸出のせいだと思います。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です