名前にスペースを含むいくつかのファイルを含むディレクトリがある場合
$ 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
使用すると不要なようです。+
\;
その理由は何ですか?
答え1
コマンドはfind
コマンドを直接実行します。このコマンド(filename引数を含む)は、シェルまたはファイル名を変更できる他の項目によって処理されません。とても安全です。
{}
コマンドラインに表示されているファイル名をエスケープする必要はありませんfind
。
find
ディスクの元のファイル名をコマンドの内部パラメータのリスト(-exec
あなたの場合はcp
コマンド)に直接渡します。
答え2
質問は2つの部分に分けられます。
- どのようにする
find
-exec
ファイル名にスペースが含まれている問題なくプログラムを呼び出すことができます。 - このオプションの利点は何ですか
-print0
?
1つ目find
は、実際には、次の関連する呼び出しセットの1つであるシステム呼び出しを作成することです。「実現する」。ファイル名をこの呼び出しに直接引数として渡し、ファイル名に関する情報を失うことなく(新しいプロセスを作成した後)呼び出しに直接渡します。
SVR4ユーティリティの特徴は基本的な+ターミネータ
find
です。-exec
これにより、ファイル名の特殊文字(特に新しいチーム文字)は一緒にグループ化され、これらのファイル名がにパイプされている場合は発生しませんxargs
。他の実装では、この問題を解決するための追加の方法が追加されています。特に、ファイル名を-print0
作成するためにヌルバイトターミネータを使用する基本的な実装があります。これはここで考慮されたが、採用されていない。 NULLターミネータを使用することは、-print0
findの出力を処理するすべてのユーティリティが、現在読んでいるNULLターミネータを解析するための新しいオプションを追加する必要があることを意味します。
それ」特にPrimaryは、問題をさまざまな方法で解決するGNUを意味します。FreeBSDもこれをサポートします-print0
。find
xargs
find
そしてxargs
。オプションを追加すると-0
(注マニュアルページ)xargs
を呼び出すと、プログラムは "ヌルバイト"文字で終わる行を受け入れます。順番にxargs
呼び出される実装する- 実行する機能それ働く関数と関数の主な違い-print0
は、前者はパイプを介してファイル名を渡し、後者はそうではないということです。開発者はほとんどすべての機能の用途を見つけることができます。パイプラインも例外ではありません。-0
+
OPの例に戻り、次に-t
見つからないオプションを使用します。cp
POSIX CP。代わりに提供される拡張です(「非標準機能」とも呼ばれます)。GNU CP。-0
拡張機能はxargs
この例を改善しませんが、他の状況で効果的に使用できます。+
GNUがfind
許可する移植可能な選択肢があることを覚えておいてください。
答え3
(これは説明でなければなりませんが、大きすぎます。)
実験が好きな人のために:
渡された場所引数を一覧表示するスクリプトを作成し、名前を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
$dirディレクトリから実行してくださいfind
:
find "$dir" -exec ./list_positional_parameters.sh '{}' ';' | less
予想どおり、名前にスペースがあるかどうかにかかわらず、すべての呼び出しにはファイル名という1つのパラメータしかありません。