サブフォルダー内の特定の拡張子を持つすべてのファイルに対してエレガントな方法でアクションを実行するにはどうすればよいですか?


17

私の現在の最善策は:

for i in $(find . -name *.jpg); do echo $i; done

問題:ファイル名のスペースを処理しません。

注:「tree」コマンドなど、これをグラフィカルに行う方法も気に入っています。


単純に引用符を付けることはできません$iか?私はそれをし、それはうまく動作します。そのアプローチに何か問題がありますか?
ウマルファルークそのKhawaja

回答:


26

正規の方法は

find . -name '*.jpg' -exec echo {} \;

(置き換える\;+に複数のファイルを渡すecho時)

または(GNU固有ですが、一部のBSDでも同様です)

find . -name '*.jpg' -print0 | xargs -r0 echo

zsh:

for i (**/*.jpg(D)) echo $i

2
xargs -0を使用している場合、find -0と一致する必要があります
-itsbruce

1
@MichaelKjörling、引用符なし{}でも違いはありません。{}は、シェルではなく、findによって展開されます。(少なくともUnix準拠の)のechoようなエスケープシーケンスを展開するものを使用しないことは改善されます。\becho
ステファンシャゼル

1
@schよろしいですか?findmanページショーfind . -type f -exec file '{}' \;EXAMPLESセクション。たぶん、いくつかのシェルはブレースを特別に扱うでしょう。
クエーサードンキー

1
引用符は害を与えませんが、違いはありません。全ては'{}'\{\}{}"{}"'{'}「{」および「}」は、2つの文字を見つけるために、1つの引数にシェル(どのボーン状シェル)によって展開されます。「検索」を「エコー検索」に置き換えるかprintf '<%s>\n' find、再確認する場合。
ステファンシャゼル

@QuasarDonkey unix.stackexchange.com/questions/8647/を参照してください...
ジル「SO-悪であるのをやめ

2

より良い答えがすでに与えられています。

ただし、指定したコードの問題はスペースだけではないことに注意してください。タブ、改行、ワイルドカード文字も問題です。

IFS='
'
set -f
for i in $(find . -name '*.jpg'); do echo "$i"; done

その場合、改行文字のみが問題になります。


1

あなたが述べたことは、人々がファイル名を読み込もうとするときに直面する基本的な問題の一つです。時々、知識が限られていて、ファイルやフォルダーの構造について誤解している人は、「UNIXではすべてがファイルである」ことを忘れがちです。そのため、ファイル名はスペースを含む2つ以上の単語で構成できるため、スペースを処理する必要があることを理解していません。

解決策:したがって、これを行うためのよく知られた方法の1つは、クリーンな読み取りを行うことです。

ここで、存在するすべてのファイルを読み取り、変数に保持します。次に、必要な処理を行うときは、スペースでファイル名を保持する引用符内にその変数を保持する必要があります。これはそれを行うための基本的な方法の1つですが、ここで他の人から提供された他の答えも同様に機能します。

脚本 :

 find /path/to/files/ -iname "*jpg" | \
  while read I; do
   cp -v --parent "$I" /backup/dir/
  done

ここでは、ファイルへのパスと読み取り中のファイルを変数I内に保持することでファイルを読み取ります。これは、後で処理するときに引用して、スペースを正しく処理するように処理します。

これが何らかの形であなたを助けることを願っています。


1
「すべてがファイル」とは、他の何かを指します。ソリューションはGUN固有であり、ファイル名のバックスラッシュまたは改行文字に対応していません。シェル(IMO)の「while read」ループは、多くの場合、シェルスクリプトの不適切な実行を示しています。
ステファンシャゼラス

@sch:ハァッ、そして私はかつて考えていた、それは大丈夫です。それを指摘してくれてありがとう。私はおそらくそれをもっと見る必要があります。
ダークナイト

申し訳ありませんが、上記の「GUN」ではなく「GNU」を意味しました(これらがアナグラムであることに
気付い

1

単純でfindかつbash

find . -name '*.jpg' -exec bash -c '
    echo "treating file $1 in bash, from path : ${1%/*}" 
' -- {} \;

この$1ように、基本的なスクリプトのように、bashで使用して、優れたパースペクティブを開き、高度な(またはそうでない)タスクを実行します。

より効率的な方法(すべてのファイルに対して新しいbashを開始することを避けるため):

find . -name '*.jpg' -exec bash -c 'for i do
    echo "treating file $i in bash, from path : ${i%/*}" 
  done' -- {} +

0

bashの最近のバージョンでは、次のglobstarオプションを使用できます。

shopt -s globstar
for file in **/*.jpg ; do
    echo "$file"
done

単純なアクションの場合、ループを完全にスキップすることもできます。

echo **/*.jpg

これはzsh(機能の由来)およびksh93(with set -G)で動作しますが、bashバージョンはgrep -rディレクトリへのシンボリックリンク(find -Lまたは同等のzsh ***/*.jpg)。また、findとは反対に、dotfilesは省略され、dotdirsには下がらないことに注意してください(デフォルト)。
ステファンシャゼル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.