Linuxで「検索」するだけでファイル名を取得する方法は?


266

ディレクトリ内のすべてのファイルに対して検索を使用しているので、パスのリストを取得します。ただし、必要なのはファイル名だけです。つまり、私は取得し./dir1/dir2/file.txt、取得したいfile.txt

回答:


359

GNU では、そのfindための-printfパラメーターを使用できます。例:

find /dir1 -type f -printf "%f\n"

9
明らかに答えですが、詳細が欠けています。
Jason McCreary

25
これはGNU専用です
オサマFエリアス

3
複数のファイルタイプ(-oスイッチ)を使用している場合、これは機能しません
Urchin

9
find:-printf:unknown primary or operator
holms

@Urchin正しいロジックがある限り(つまり-o、暗黙より優先順位が低い-aため、-o引数をグループ化したい場合が多いため)、理由はありません
モニカを復活させてください

157

検索に-printfオプションがない場合は、basenameを使用することもできます。

find ./dir1 -type f -exec basename {} \;

17
セミコロンを引用することは明確にするための別の方法である:... {} ';'
davidchambers

28

-execdir現在のファイルを自動的に保持するを使用します。{}次に例を示します。

find . -type f -execdir echo '{}' ';'

$PWD代わりに使用することもできます.(一部のシステムでは、前面に余分なドットが生成されません)。

それでも余分なドットがある場合は、代わりに次のコマンドを実行できます。

find . -type f -execdir basename '{}' ';'

-execdir utility [argument ...] ;

-execdir主は同じである-execユーティリティがディレクトリから実行されることを除いて、主要な現在のファイルを保持しています

+代わりに使用すると;{}ユーティリティの呼び出しごとに可能な限り多くのパス名に置き換えられます。つまり、すべてのファイル名を1行で出力します。


./filename代わりに私は得ていますfilename。ニーズに応じて、問題ない場合があります。
user276648 2017年

@ user276648の$PWD代わりにで試してください.
ケノーブ2017年

24

GNU findを使用している場合

find . -type f -printf "%f\n"

または、Ruby(1.9+)などのプログラミング言語を使用できます。

$ ruby -e 'Dir["**/*"].each{|x| puts File.basename(x)}'

あなたがbash(少なくとも4)ソリューションを好むなら

shopt -s globstar
for file in **; do echo ${file##*/}; done

:私は、ヘルプsleskeにあなたの答えに触発されたserverfault.com/a/745968/329412
Nolwennig

11

ファイル名のみに対して何らかのアクションを実行したい場合は、 basenameするのが難しいがあります。

例えばこれは:

find ~/clang+llvm-3.3/bin/ -type f -exec echo basename {} \; 

basenameをエコーするだけ/my/found/pathです。ファイル名で実行したい場合は必要ありません。

しかし、その後xargs、出力することができます。たとえば、別のディレクトリの名前に基づいてディレクトリ内のファイルを強制終了するには、次のようにします。

cd dirIwantToRMin;
find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \; | xargs rm

エコーしないでください–find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \;
commonpike


1

-execそして-execdir遅いです、xargs王様です。

$ alias f='time find /Applications -name "*.app" -type d -maxdepth 5'; \
f -exec basename {} \; | wc -l; \
f -execdir echo {} \; | wc -l; \
f -print0 | xargs -0 -n1 basename | wc -l; \
f -print0 | xargs -0 -n1 -P 8 basename | wc -l; \
f -print0 | xargs -0 basename | wc -l

     139
    0m01.17s real     0m00.20s user     0m00.93s system
     139
    0m01.16s real     0m00.20s user     0m00.92s system
     139
    0m01.05s real     0m00.17s user     0m00.85s system
     139
    0m00.93s real     0m00.17s user     0m00.85s system
     139
    0m00.88s real     0m00.12s user     0m00.75s system

xargsの並列処理も役立ちます。

おかしなことに、私はxargsなしの最後のケースを説明できません-n1。正しい結果が得られ、最速です¯\_(ツ)_/¯

basename1つのパス引数のみを受け取りますがxargs、それらをすべて送信します(実際には5000)-n1。Linuxとopenbsdでは動作しません。macOSのみです...)

Linuxシステムのいくつかの大きな数値は、どのように-execdir役立つかを確認するためのものですが、パラレルよりもはるかに低速ですxargs

$ alias f='time find /usr/ -maxdepth 5 -type d'
$ f -exec basename {} \; | wc -l; \
f -execdir echo {} \; | wc -l; \
f -print0 | xargs -0 -n1 basename | wc -l; \
f -print0 | xargs -0 -n1 -P 8 basename | wc -l

2358
    3.63s real     0.10s user     0.41s system
2358
    1.53s real     0.05s user     0.31s system
2358
    1.30s real     0.03s user     0.21s system
2358
    0.41s real     0.03s user     0.25s system

1
もう1つデータポイントです。openbsdでは、長時間実行findする-execdirと、新しいプロセスの作成が比較的コストのかかる操作になるため、これが最も速くなります。
マイナス

1

正直なところbasenamedirname解決策は簡単ですが、あなたはまた、このアウトをチェックすることができます。

find . -type f | grep -oP "[^/]*$"

または

find . -type f | rev | cut -d '/' -f1 | rev

または

find . -type f | sed "s/.*\///"

0

他の人が尖っアウトを持っているとして、あなたは組み合わせることができますfindbasenameが、デフォルトではbasename(いずれかを使用して実行ファイルがパスごとに一度起動する必要がありますので、プログラムは、一度に一つのパス上でのみ動作しますfind ... -execfind ... | xargs -n 1潜在的に遅くなる可能性があります、)。

-aonオプションを使用するbasenameと、1回の呼び出しで複数のファイル名を受け入れることができます。つまり、xargsなし-n 1でを使用して、パスをグループ化して、はるかに少ない数の呼び出しにまとめることができます。basename化できます。これ、より効率的になります。

例:

find /dir1 -type f -print0 | xargs -0 basename -a

ここで私は含まれてきた-print0とし-0、ファイルとディレクトリの名前内の空白に対処するために(一緒に使用する必要が。

xargs basename -aとのxargs -n1 basenameバージョン間のタイミングの比較を以下に示します。(like-with-likeの比較のために、ここで報告されるタイミングは最初のダミー実行の後であるため、ファイルメタデータがすでにI / Oキャッシュにコピーされた後で両方とも実行されます。)cksumどちらの場合も、出力が使用する方法に依存しないことを示すためだけです。

$ time sh -c 'find /usr/lib -type f -print0 | xargs -0 basename -a | cksum'
2532163462 546663

real    0m0.063s
user    0m0.058s
sys 0m0.040s

$ time sh -c 'find /usr/lib -type f -print0 | xargs -0 -n 1 basename | cksum' 
2532163462 546663

real    0m14.504s
user    0m12.474s
sys 0m3.109s

ご覧のように、basename毎回起動することを回避する方がはるかに高速です。


@minusfからの回答をより詳しく読むと、Macではbasename追加のコマンドライン引数を必要とせずに複数のファイル名を受け入れることがわかります。ここでの使用は-aLinux上です。(basename --version教えてくれbasename (GNU coreutils) 8.28ます。)
アラニウィ

-3

私は最新のファイル名だけを与える解決策を見つけました(makandracardsページで):

ls -1tr * | tail -1

(ありがとうはArne Hartherzに行きます)

私はそれを使用しましたcp

cp $(ls -1tr * | tail -1) /tmp/

2
これは質問にまったく答えません。
kenorb 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.