$()が正しく拡張されないのはなぜですか?

$()が正しく拡張されないのはなぜですか?

vlcを使用してディレクトリ内のすべての.mp3ファイルを再生したいので、次のようにします。

vlc $(find ~/Documents/music -name "*.mp3" -exec "echo \"{}\"" \;)

問題は、「vlc:不明なオプションまたは必須パラメータ '-D'がありません」というメッセージが表示されることです。それはおそらく構文解析の問題でしょう。

それではファイルごとにしてみましょう:

echo $(echo $(find ~/Documents/music -name "*.mp3" -exec echo "\"{}\" \n " \;) | head -n 1)

私は得る:

"/home/XXX/Documents/music/My Folder/1 - track/the name of track.mp3"

私が実行したとき:

vlc "/home/XXX/Documents/music/My Folder/1 - track/the name of track.mp3"

効果がある

しかし、私が走るとき

vlc $(echo $(find ~/Documents/music -name "*.mp3" -exec echo "\"{}\" \n " \;) | head -n 1)

私は得る:

cannot open file /home/XXX/the (No such file or directory)

vlcの引数が正しく引用されていない場合、これは意味があります。しかし、そうですか?それでは、なぜ引用符で囲まれていない文字列としてvlcに渡されますか?

答え1

拡張出力では見積もりは処理されません。$(echo '"foo bar"')orを実行すると、$(echo "\"foo bar\"")デフォルトのコマンドの引数は"fooandですbar"。リテラル引用符と2つの異なる引数を使用します。噴射

デフォルトでは、単語の区切りはすべてのスペース、スペース、または改行文字で発生するため、出力はどのスペースがファイル名の一部か、どのスペースがそれを区切るために使用された印刷内容の一部であるかを知るfindことはできません。find一般的な場合でも、ファイル名に改行文字を含めることができるため、区別できません。

あなたができることは次のとおりです。

find ... -print0 | xargs -0 vlc 

または

find ... -exec vlc {} +

最初は、findNULバイトで区切られたファイル名を出力し、xargs予想される内容を知らせます。ただし、すべてのシステムにfind -print0およびがあるわけではありませんxargs -0

2番目の関数find自体が起動し、尾vlc{} +複数のファイル名をvlc

大量のファイルを探していて、1つのコマンドラインに入ることができない場合は、両方のファイルをvlc複数回起動できます。

望むより:

デバッグにこれを使用すると、引数echoが空白で連結され、echo foo barとを区別できなくなるので実際には動作しませんecho "foo bar"

答え2

拡張は$()正確ですが、シェルはあなたが思うよりも多くの結果を提供します。また、パス名に文字通り引用符を追加することは(どこかで使用しない限り)ほとんど正しいことではありませんeval

以下のすべてのMP3ファイルを再生するには、以下を~/Documents/music使用しますvlc

find ~/Documents/music -type f -name '*.mp3' -exec vlc {} +

vlcこれにより、一度にできるだけ多くのMP3ファイルが実行されます。

findすべて一緒に使用してスキップするには:

shopt -s globstar
vlc ~/Documents/music/**/*.mp3

この方法は、MP3ファイルの数が少ない限り機能します(この場合、パラメータリストが長すぎてエラーが発生します)。

globは**ファイル階層と「再帰的に」一致しますが、シェルを使用して有効にする必要がありますshopt -s globstarbashこのzshglobはデフォルトで有効になっています)。


注文

vlc $(echo $(find ~/Documents/music -name "*.mp3" -exec echo "\"{}\" \n " \;) | head -n 1)

最初に実行するfindと、パイプラインが出力されますheadecho

"/home/XXX/Documents/music/My Folder/1 - track/the name of track.mp3"

その後、シェルは文字列を文字列内の単語、、、、、、および"/home/XXX/Documents/music/Myスペースに分割します。Folder/1-track/thenameoftrack.mp3"

vlcそれではそれと呼ばれるでしょう。分離議論。特に、この-パラメーターはオプションとして誤認される可能性があり、他のパラメーターは別々のパス名オペランドとして扱われる可能性があります。

これについて詳しく説明します。

関連情報