
免責事項:いいえlsやgrepなどの特定のコマンドに関連していますが、例では使用しましたが、これはbashに近いです。
「特定の単語」をすべて含むファイルセット(ls -l)のファイルサイズ、タイムスタンプ、権限/所有者/グループを見たいとしましょう。通常私はこうする:
ls -l $( grep -l 'a certain word' * )
これは、「filename」というファイルなど、ファイル名にスペースが含まれるまで魔法のように機能します。これにより、lsは2つのファイル名「file」と「name」を見つけることができません。
Bashスクリプトには、この問題のバリエーションを解決するためのおなじみの方法があります。コマンドラインからファイル名をスクリプトに渡すと、${1}、${2}などとして引用されます。 「${1}」、「${2}」などの引用符で囲むことで問題はなく、空白があっても処理できます。みんな「${@}」を使用してすぐにファイル名を表示すると、各パラメータが正しく一覧表示され、空白があってもそのまま残ります。リストされたgrep / lsスタイルの問題を解決するためのメカニズムが見つかりませんでした。以上。拡張コマンドを引用符で囲むと、$( )
すべてのファイルがlsの1つの大きな引数として扱われます。
私は通常このようにこの問題を解決しますがgrep -l .... | while read file; do ls -l "${file}"; done
、本当にそうしてはいけません。これにより、日付/サイズ/その他(たとえばls -ltr $( grep -l ....)
)でファイルを並べ替えることはできません。
私はいつもbashの解決策があると思いましたが、まだそれに触れていません。この問題は時々しか現れず、通常修正されますが、今は方法があると思うほど私を悩ませます。 。
はい、これを見て、使用している特定のツール(tarなど)で解決された問題、またはその問題がコマンドによって異なるため、答えは「申し訳ありませんが、ここまでは行けません」です。この問題を解決するには、より多くの時間を費やしたり、魔法を見つけるのではなく、スペースを含む結果として提供されたファイル名を処理し、それを別のコマンドに引数として渡すように要求します。私は、同一でない質問を提供するよりも、この質問に答えがない状態(解決策がないことを証明すること)を好みます。
答え1
よく。 @don_crisstiはすでに答えを提供しています。grepの場合コメントに。しかし、これは実際にはgrep
ORに関するものではないと述べたので、ls
そのコマンドを使用しないように問題のコマンドを書き直します。
私の考えでは、あなたが望むものは次のとおりです。
do-something-with $(produce-list-of-files)
いずれかのコマンドの出力は、他のコマンドのコマンドライン引数として入力する必要があります。この目的のためのユーティリティがあり、それを呼び出します。xargs
(マンページ)。
ファイル名が「good」の場合、これを行うことができます。
produce-list-of-files | xargs do-something-with
xargs
ファイル名にスペースを含めることができますが、改行で区切ることができる場合は、分割しないでください。どの空白(改行のみ可能):
produce-list-of-files | xargs -d '\n' do-something-with
ファイル名に改行文字を含めることができる場合は、リストはNUL( '\ 0'、値が0のバイト)で区切られ、xargs
それをサポートするファイル名が必要です。さまざまなユーティリティの少なくとも一部のバージョンは、改行文字の代わりにNULで区切られたファイルのリストをサポートしています。これらのツールのGNUバージョンでは、少なくとも、find -print0
およびsort -z
。記号grep -Z
はまたはです。だから:xargs
--null
-0
produce-list-of-files -0 | xargs -0 do-something-with
cat
とを使用して実行する例ls -l
:
$ touch "abba acdc" "foo bar" $'new\nline'
$ echo -en "abba acdc\0foo bar\0new\nline\0" > list
$ cat list | xargs -0 ls -l
-rw-r--r-- 1 itvirta itvirta 0 Aug 2 01:23 abba acdc
-rw-r--r-- 1 itvirta itvirta 0 Aug 2 01:23 foo bar
-rw-r--r-- 1 itvirta itvirta 0 Aug 2 01:23 new?line
答え2
改行で区切られたアイテムのリスト(ファイル名など)を生成するコマンドがあり、アイテム自体に改行を含めることができる場合、ここからそのアイテムに移動することはできません。
grep -Z
一部のシステムの一部のコマンドは、GNU grep()、GNU sed(sed -z
)、GNU awk(gawk RS='\0' ORS='\0'
)、GNU、およびBSD find()など、改行ではなくNULLバイトで区切られたリストを作成または管理できます。これで次のようにfind -print0
なります。xargs -0
空白で区切られた項目のリストからコマンドを実行します。
find … -print0 | sed -z … | xargs -0 frob …
ファイル名に改行文字が含まれていないと仮定したい場合は、分割+glob演算子(つまり、引用符なしで拡張)を使用して改行で区切られたリストを分割できます。ゴービングをオフにして改行文字で分割(変数)set -f
するように区切り記号を設定する必要があります。IFS
IFS='
'; set -f
ls -l -- $(grep -l 'a certain word' *)
set +f; unset IFS
最後の行はデフォルト設定を復元します。設定を正確に保存してset -f
復元するIFS
ことは可能ですが、面倒です。
後で処理するために出力を保存する必要がある場合は、出力を定義し、データを配列に保存するときに分割するか、使用時に分割してデータを文字列に保存できます。配列の使用(ksh、bash、またはzshが必要):
IFS='
'; set -f
files=($(grep -l 'a certain word' *))
set +f; unset IFS
…
ls -l -- "${files[@]}"
文字列を使用してください:
files=$(grep -l 'a certain word' *)
IFS='
'; set -f
ls -l -- $files
set +f; unset IFS
また、見ることができますスペースやその他の特殊文字が原因でシェルスクリプトが停止するのはなぜですか?