「find -exec」はどのようにファイル名にスペースを渡しますか?


14

名前にスペースが含まれるファイルを含むディレクトリがある場合、たとえば

$ ls -1 dir1
file 1
file 2
file 3

これらすべてを次のように別のディレクトリに正常にコピーできます。

$ find dir1 -mindepth 1 -exec cp -t dir2 {} +

ただし、の出力にfind dir1 -mindepth 1はエスケープされていないスペースが含まれます。

$ find dir1 mindepth 1
dir1/file 1
dir1/file 3
dir1/file 3

print0代わりに使用する場合print、出力にはエスケープされていないスペースが含まれています。

$ find dir1 mindepth 1 -print0
dir1/file 1dir1/file 2dir1/file 3

を使用してこれらのファイルを手動でコピーcpするには、スペースをエスケープする必要があります。しかし、私がコマンドを使用するか、コマンドの最後に関係なく、cpの引数が来るとき、これは不要であるようです。find+\;

この理由は何ですか?

回答:


8

findコマンドが直接コマンドを実行します。filename引数を含むコマンドは、シェルまたはファイル名を変更する可能性のある他のものによって処理されません。とても安全です。

あなたは、で表されたファイル名エスケープする必要はありませんことを正しいもの{}findコマンドラインが。

find生のファイル名をディスクから-execコマンドの内部引数リストに直接渡しますcp。あなたの場合はコマンドです。


1
一言で言えば、find..execそれ自体で奇妙なファイル名を処理することができます。
heemayl

2
Linuxクラブの最初のルールは、lsを解析しないことです
Sergiy Kolodyazhnyy

5

質問は2部構成です。

  • ファイル名に埋め込まれたスペースの問題にぶつかることなく、どのように使用してプログラムを呼び出すこと findできますか?-exec
  • -print0オプションは何が良いですか?

最初findは、システムコールを作成することです。実際には、「exec」と呼ばれる関連するコールのグループの1つです。ファイル名を引数としてこの呼び出しに直接渡します。この呼び出しは、ファイル名に関する情報を失うことなく(新しいプロセスの作成後に)直接渡されます。

POSIX find機能+は、次のように理論的根拠で説明されています。

SVR4のfindユーティリティの機能は、-execプライマリ+ターミネーターでした。これにより、特殊文字(特に改行文字)を含むファイル名を、そのようなファイル名がにパイプされた場合に発生する問題なくグループ化できましたxargs。他の実装では、この問題を回避するために他の方法、特に-print0ヌルバイトターミネータでファイル名を書き込んだプライマリが追加されています。これはここで考慮されましたが、採用されませんでした。nullターミネーターを使用すると、findの-print0出力を処理しようとするユーティリティ は、現在読み込んでいるnullターミネーターを解析するための新しいオプションを追加する必要がありました。

つまり、「とりわけ-print0原発」はGNUを意味findし、xargsこれは別の方法で問題を解決します。また、FreeBSD findおよびでもサポートされていますxargs。呼び出しに-0オプション(マニュアルページを参照)を追加した場合xargs、そのプログラムは「null byte」文字で終了する行を受け入れます。次に、exec -functionsをxargs呼び出し作業を行います。and 機能と機能の主な違いは、前者がファイル名をパイプで渡すのに対し、後者はパスを渡さないことです。開発者は、ほとんどすべての機能の用途を見つけます。パイプも例外ではありません。-print0-0+

OPの例に戻ります。この例では、POSIX cpにはない-tオプションを使用しています。むしろ、GNU cpが提供する拡張機能(別名「非標準機能」)です。の拡張はこの例を改善しませんが、それを効果的に使用できる他の場合があります。GNUが受け入れるポータブルな代替があることに留意してください。cp-0xargs+find


-1

これはコメントである必要がありますが、大きすぎます。

物事を試してみたい人のために:

渡された定位置パラメーターをリストするスクリプトを作成し、それを呼び出しますlist_positional_parameters.sh

#!/bin/bash

# http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_09_07.html
# Try globbing patterns, e.g. "X[[:digit:]][[:digit:]]" to see what happens

if [ $# -lt 1 ]; then
   echo "Usage: $0 and then at least one parameter"
   exit 1
fi

counter=1

while (($#)); do
   echo "$counter = '$1'"
   # pop positional argument 1 off the stack of positional arguments
   shift
   (( counter++ ))
done

findいくつかのディレクトリ$ di​​rで実行します:

find "$dir" -exec ./list_positional_parameters.sh '{}' ';' | less

予想どおり、名前にスペースが含まれているかどうかに関係なく、すべての呼び出しにファイル名という1つのパラメーターしかありません。


1
また、printflike printf '"%s"\n' "$@"を使用して、引用符で囲まれたすべての位置引数を印刷して視覚的に確認することもできます。
クサラナナンダ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.