Bashスクリプトで奇妙な文字を正しくエスケープする方法は?

Bashスクリプトで奇妙な文字を正しくエスケープする方法は?

私はスクリプトを書いたりコマンドを探したりする専門家ではありません(単に警告です)。私はすべてのmp3 Podcastを自分の携帯電話に移動できるフォルダに移動するスクリプトを作成しようとしています。

そのため、私が作成したスクリプトはすべてのmp3(パスが奇妙なファイルも含む)を移動する必要があります。以下のようにスクリプトを作成しましたが、意図したとおりに動作しているようですが、引き続き次のエラーが発生します。

find /home/jason/gPodder/ -name '*.mp3' -exec bash " cp '{}' /home/jason/gPodder/mp3/ " \;
Which returns:    
bash:  cp '/home/jason/gPodder/Downloads/The Documentary/TheDocumentary20170823-GoingGreenInTheOilState.mp3' /home/jason/gPodder/mp3/ : No such file or directory 

しかし、上記のbash "コマンド"をコピーすると正常に動作します。スクリプトのエラーが何であるかを理解するのに役立ちます。

ありがとう

答え1

〜のように@Kusalanandaが言った。-c、インラインスクリプトを使用する機能はありません。

{}しかし、それにもかかわらず、任意のコマンドインジェクションの脆弱性(例'$(reboot)'.mp3で呼び出されたファイル)になる可能性があるシェルコードには含めないでください。代わりに、インラインスクリプトのパラメータとして作成します(インラインスクリプトが実際に必要であると仮定し、これは単なるcp例です)。

find ... -exec sh -c 'cp "$1" /home/jason/gPodder/mp3' sh {} \;

bash(これだけのためにもする必要はありません。sh意図も大丈夫です。)

または、より良い方法は、一度に複数の引数を渡すことですcp

find ... -exec sh -c 'cp "$@" /home/jason/gPodder/mp3' sh {} +

GNUを使用すると、cp次のこともできます。

find ... -exec cp -t /home/jason/gPodder/mp3 {} +

答え2

必要以上に複雑にしないでください。

find /home/jason/gPodder/ -name '*.mp3' -exec cp {} /home/jason/gPodder/mp3/ \;

または多分

find /home/jason/gPodder/ -type f -name '*.mp3' -exec cp {} /home/jason/gPodder/mp3/ \;

一般ファイルのみが考慮されます。

同じ名前のファイルがターゲットフォルダにない場合にのみファイルをコピーしてください。一部のcp実装では、このオプションをサポートするか、次のリダイレクトされた標準入力を-n使用できます(ただし、ターゲットタイプがディレクトリの場合は機能しません)。次のようにしてください。-i/dev/null

find /home/jason/gPodder/ -type f -name '*.mp3' \
    ! -execdir test -e /home/jason/gPodder/mp3/{} \; \
    -exec cp {} /home/jason/gPodder/mp3/ \;

-execdirPOSIX標準の拡張ですが、多くの最新の実装でサポートされてfindいます。find同様に実行されますが、-exec見つかったコンテンツの親ディレクトリを作業ディレクトリとして使用してコマンドを実行します。また、フルパスではなく、{}見つかった項目(file.mp3または実装./file.mp3に応じて)のデフォルト名になります。find望むよりman find


このエラーはで発生しますbash "somecommand"bashこのように呼び出すと、一連のシェルコマンドではなくスクリプトファイルへのパスがbash必要になり、somecommand指定した名前のスクリプトが見つかりません。

一連のシェルコマンドを実行する必要がありますbash -c "somecommand"

ただし、この場合は-exec cp上記の方法または次の方法を使用してください。Stefan Chazerasの答え

答え3

他の人々は価格設定と実行の問題を指摘した。

find -execを使用する代わりに、xargsとcpのリストとパイプのリストを見つけることをお勧めします。 print0オプションを使用すると、ファイル名とディレクトリ名の「面白い」文字を防ぐのに役立ちます。

例えば

find sourcepath -name \*.mp3 -print0 \
    | xargs -0 cp -t destinationpath

これの利点は、xargsがfindから複数のファイル名を収集して同時にcpに渡すので、各ファイルに対して1 cp呼び出しを実行する代わりに、各cpインスタンスが20または100個のファイルをコピーできることです。 xargsはcpコマンドラインに十分なファイル名を入力します。

xargs に -P n オプションを追加すると、複数の cp プロセスが並列に開始されます。

これは、ファイルが宛先mp3フォルダと同じファイルシステムにあると仮定します。 cpに-lを追加すると、ファイルをコピーするのではなく、ターゲットにハードリンクされます。

例えば

find sourcepath -name \*.mp3 -print0 \
    | xargs -0 -P 5 \
    cp -l -t destinationpath

関連情報