findコマンドを使用してファイル名をリストするがパスはリストしない方法は?

Jan 06 2021

オンラインでいくつかの回答を確認しましたが-name、コマンドにパラメーターがあると機能しません(何か間違ったことをしているのかもしれませんが、よくわかりません)。私は何をしたいのですが(いないディレクトリ/パス)のみのファイル名のリストであり、より複雑にし、私が使用して結果をフィルタリングする必要があるので、私は、別の拡張子を持つ同じファイル名を持っている-name-o、トラブルはそのIの提案です-printfまたはのいずれかを使用しているのを見ましたがbasename、があるとうまく機能しません-name *.txt -o name *.pdf。この問題を解決する他の方法はありますか?

私のファイルの例:

/dir1/dir2/dir3/dir4/
                    /file1.txt
                    /file1.pdf
                    /file1.ods ...etc.

リストごとに1つ以上のタイプのファイルをリストすることにのみ興味があります(-name結果をフィルタリングするためにを使用して)。

1つのfindコマンドだけを使用してそれを実行することは可能ですか、それとも2つのステップで実行する必要があります(結果を一時ファイルに保存してから、一時ファイルからディレクトリをフィルタリング/削除します)?私が達成しようとしている結果は、1行あたりのファイル名を含むテキストファイルです。

file1.txt
file1.pdf
file1.ods
file2.txt
file2.pdf
etc.

私が使っていたコマンドは

find /dir1/dir2/dir3/dir4/ -type f -name '*.txt' -o -name '*.pdf' -o -name '*.ods' -printf "%f\n"

私はGNUfindを使用しています。

更新

\(...\)αғsнιηが思い出したように、私は入れなければならないことが判明しました

回答

3 αғsнιη Jan 06 2021 at 21:02

論理ORモードで複数の式を使用する場合-o\( ... \)、それらをすべてで囲む必要があります。そうしないと、最後の式の結果が常に尊重されます。また-printf '%f\n'、先頭のディレクトリが削除された状態でのみファイルの名前を出力するために使用されます。

find . -type f \( -name '*.pdf' -o -name '*.txt' \) -printf '%f\n'

についてはman find、演算子セクションを参照してください( expr )

オペレーター
..。

(expr)
優先順位を強制します。括弧はシェルに固有のものであるため、通常は引用符で囲む必要があります。

したがって、\( ... \)または'(' ... ')'(括弧の前後の空白が重要です)を使用してそれらをエスケープできます。

1 Kusalananda Jan 06 2021 at 22:58

すでに述べたように、-nameテストを括弧内にグループ化する必要があります。これらの括弧\( ... \)は、たとえば'(' ... ')'シェルから保護するために、エスケープするか引用符で囲む必要があります(そうでなければサブシェルを指定します)。

標準を使用しfind、ファイル名のサフィックスの処理を少し簡単にします。

set -- txt pdf ods

for suffix do
    set -- "$@" -o -name "*.$suffix"
    shift
done
shift

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename {} \;

これは最初に、位置パラメータを表示したいファイル名サフィックスのリストに設定し(これがスクリプトの場合はコマンドラインから取得することもできます)、-nameテストのORリストを作成します。これは、findコマンドラインで使用されます。

次に、findコマンド自体が、basename見つかった名前ごとにユーティリティを呼び出します。

別の方法として、代わりにパラメーター置換を使用して、各パス名のファイル名コンポーネントを除くすべてを削除することもできますが、そのためには、パス名をインラインsh -cスクリプトに渡す必要があります。

# [...] as before [...]

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec sh -c '
    for pathname do
        printf "%s\n" "${pathname##*/}"
    done' sh {} +

私は、これは使用して迅速に変化よりも実行するために期待されるbasename、少なくともGNUであるが、ハンドルには多くのファイル名がある場合、basenamecoreutilsのから、あなたが使用できる-aかが--multipleとても好きです。

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename -a {} +

これはbasename、可能な限り少ない回数で呼び出します。しかし、繰り返しになりますが、coreutilsがインストールされている場合は、GNUをfind使用-printf '%f\n'したfindutilsもある可能性があり、同じことを行うために使用できます。