52

Linuxコマンドラインで検索のファイル名部分をエコーアウトしたいと思います。私は以下を使おうとしました:

find www/*.html -type f -exec sh -c "echo $(basename {})" \;

find www/*.html -type f -exec sh -c "echo `basename {}`" \;

そして、テキストのさまざまな部分をエスケープして引用する他の多くの組み合わせ。その結果、パスは削除されません。

www/channel.html
www/definition.html
www/empty.html
www/index.html
www/privacypolicy.html

なぜだめですか?

更新:以下に実用的な解決策がありますが、「basename」が本来の機能を果たさない理由に興味があります。

4

4 に答える 4

73

あなたの最初の試みの問題:

find www/*.html -type f -exec sh -c "echo $(basename {})" \;

これは、コマンドが実行される$(basename {})前に、コードが1回実行されることです。findシングルの出力basename{}、それが{}ファイル名としてのベース名であるためです。したがって、findによって実行されるコマンドは次のとおりです。

sh -c "echo {}" 

見つかったファイルごとに、実行される文字列に文字が表示されるfindため、実際には毎回元の(変更されていない)ファイル名に置き換えられます。{}

動作させたい場合は、二重引用符の代わりに一重引用符を使用できます。

find www/*.html -type f -exec sh -c 'echo $(basename {})' \;

ただし、とにかく標準出力に書き込んだechoものを標準出力に繰り返すことは、少し無意味です。basename

find www/*.html -type f -exec sh -c 'basename {}' \;

もちろん、それをさらに減らすことができます。

find www/*.html -type f -exec basename {} \;

ここで一重引用符と二重引用符の違いについても説明していただけますか?

これは通常のシェルの動作です。少し異なるコマンドを実行して(ただし、ファイルの名前はwww1レベル下だけでなく、ディレクトリの下のどこにでも配置できます)、シングルクォート(SQ)バージョンとダブルクォート(DQ)バージョンを見てみましょう。指図:

find www -name '*.html' -type f -exec sh -c "echo $(basename {})" \;   # DQ
find www -name '*.html' -type f -exec sh -c 'echo $(basename {})' \;   # SQ

一重引用符は、囲まれた資料をコマンドに直接渡します。したがって、SQコマンドラインでは、起動するシェルがfind囲んでいる引用符を削除し、findコマンドはその$9引数を次のように認識します。

echo $(basename {})

シェルが引用符を削除するためです。比較すると、二重引用符で囲まれた素材はシェルによって処理されます。したがって、DQコマンドラインでは、シェル(起動するシェルではfindなく起動する find)が$(basename {})文字列の一部を確認して実行し、戻ってくるので、引数として{}渡される文字列は次のようになります。find$9

echo {}

さて、findその-execアクションを実行すると、どちらの場合も、{}(引数のために)見つけたばかりのファイル名に置き換えられますwww/pics/index.html。したがって、2つの異なるコマンドが実行されます。

sh -c 'echo $(basename www/pics/index.html)'    # SQ
sh -c "echo www/pics/index.html"                # DQ

そこには(わずかな)表記上のチートがあります—これらはシェルで入力するのと同等のコマンドです。起動されたシェルの$2は、どちらの場合も実際には引用符が含まれていません—起動されたシェルには引用符が表示されません。

ご覧のとおり、DQコマンドは単にファイル名をエコーし​​ます。SQコマンドは、basenameコマンドを実行してその出力をキャプチャし、キャプチャされた出力をエコーし​​ます。少し還元主義的な考え方は、DQコマンド-printを使用する代わりにとして書く-execことができ、SQコマンドをとして書くことができることを示してい-exec basename {} \;ます。

GNUを使用している場合は、実行が不要になるようにフォーマットディレクティブが従うことができるアクションをfindサポートします。ただし、これはGNUでのみ使用できます。ここでの残りの説明は、遭遇する可能性のあるすべてのバージョンに適用されます。-printfbasenamefindfind

于 2013-03-26T01:14:39.037 に答える
15

代わりにこれを試してください:

 find www/*.html -type f -printf '%f\n'

パイプでそれをやりたい場合(より多くのリソースが必要です):

find www/*.html -type f -print0 | xargs -0 -n1 basename
于 2013-03-26T00:47:59.563 に答える
7

これが、imagickを使用してファイルのサイズをバッチで変更し、ソースから出力ファイル名を再作成する方法です。

find . -name header.png -exec sh -c 'convert -geometry 600 {} $(dirname {})/$(basename {} ".png")_mail.png' \;
于 2014-01-17T14:45:35.377 に答える
0

私は似たようなことを成し遂げなければならず、findの出力のループを回避し、shでfindを使用することで、これらの問題を完全に回避するために述べた方法に従うことがわかりまし{}-printf

あなたはこのようにそれを試すことができます:

find www/*.html -type f -exec sh -c 'echo $(basename $1)' find-sh {} \;

要約は、「sh -c内で直接{}を参照するのではなく、引数としてsh -cに渡すと、sh-c内の数値変数を使用して参照できます」find-shです。を取り上げるためのダミー、そのようにしてそれを実行し、のため$0に使用することには、より多くの有用性があります。{}$1

の使用はecho、概念とテスト機能を単純化するためのものだと思います。他の人が述べているように、単純にエコーする簡単な方法がありますが、このシナリオの理想的な使用例は、、、cpまたはmvコマンドで見つかったファイル名を複数回参照する必要があり、取得する必要があるより複雑なコマンドを使用することです。パスを削除します。例:ソースと宛先の両方でファイル名を指定する必要がある場合、または名前を変更する場合。

したがって、たとえば、 htmlドキュメントのみをディレクトリにコピーしたい場合public_html(なぜですか?例があります!)、次のことができます。

 find www/*.html -type f -exec sh -c 'cp /var/www/$(basename $1) /home/me/public_html/$(basename $1)' find-sh {} \;

UNIXのstackexchangeで、findを使用したループに関するユーザーワイルドカードの回答は、との使用法に関するいくつかの優れた宝石に-execなりsh -cます。(ここで見つけることができます:https ://unix.stackexchange.com/questions/321697/why-is-looping-over-finds-output-bad-practice )

于 2016-11-16T18:53:09.807 に答える