
locate
「人間が読める形式」(つまり、\
先頭にスペースがない)でパスのリストを生成するようなコマンドの出力を操作する場合、その出力を別のコマンドにリダイレクトするにはどうすればよいでしょうか。
の出力は$ locate [something]
スペースを含むパスを生成するため、他のプログラムがスペースを含むパスを使用することを禁止します。たとえば、
$ du -h `locate *.doc`
これにより、スペースを含むすべてのファイルとディレクトリでエラーが発生します。(チェックマークをスペースで囲むことはできません)
答え1
を使用する具体的な理由は何ですかlocate
? これは、あなたが求めていることを実行するようです:
find . -type f -name '*doc' -exec du -h "{}" \;
そうは言っても、もしあなたが本当にlocate
またはのようなツールを使用して、その入力を別のプログラムにパラメータとして渡したい場合は、一部のツールが提供する区切り出力と入力を find
利用できます。との両方にオプション(と)があり、よりプログラムしやすい出力が得られます。これは、NUL
locate
find
locate
-0
find
-print0
xargs
その -0
口論:
find . -type f -name '*doc' -print0 | xargs -0 du -h
locate -0 '*doc' | xargs -0 du -h
答え2
同じ行を複数のコマンドに渡したい場合は、次のようにします。
#!/usr/bin/env bash
T="${IFS}" # Save off the Internal Field Separator
IFS=$'\n' # Set it to newline.
while read file_line
do
echo "--"
echo "${file_line}"
echo "--"
done <<< $(locate $1)
IFS="${T} # Set it back to the original IFS.
包むのが良いでしょうどれでも"" 内にスペースが含まれる可能性がある変数。
答え3
コマンド置換 ($(...)
または`...`
古い形式) を引用符で囲まないままにしておくと、Bourne のようなシェルで split+glob (zsh では split のみ) が呼び出されます。
分割は、$IFS
デフォルトでスペース、タブ、改行 (zsh では NUL) を含む特殊パラメータの文字に対して行われます。これが、スペース文字を含むファイル名に対してコマンドが機能しない理由です。
次のようにすることができます:
(IFS='
' # split on newline only
set -o noglob # disable glob
du -hc -- $(locate '*.doc'))
しかし、改行文字を含むファイル名がある場合は、それでも失敗します。 の出力は、locate
単に後処理可能ではありません。
ほとんどのlocate
実装には、-0
ファイル パスをNUL
区切って出力するオプションがあります。NUL はファイル パスに出現できない唯一のバイト値であるため、出力は後処理可能です。NUL で分割するだけです。
でzsh
:
IFS=$'\0'
du -hc -- $(locate -0 '*.doc')
または、明示的な NUL での分割演算子を使用する方がよいでしょう。
du -hc -- ${(0)"$(locate -0 '*.doc')"}
4.4以降ではbash
、次のようになります。
readarray -td '' files < <(locate -0 '*.doc')
du -hc -- "${files[@]}"
それでもまだ 2 つの問題が残ります。
locate
ファイルが見つからない場合は、du -hc --
引数なしで実行され、現在の作業ディレクトリのディスク使用量が表示されます。- 一方、多くのファイルを見つけた場合は、システムコール
locate
の制限に達して、execve()
引数リストが長すぎますエラー。
両方の問題は、次の操作を行うことで回避できます。
locate -0 '*.doc' | xargs -r0 du -hc --
(および-r
は、-0
の GNU 実装からの非標準の拡張であるのとxargs
同様に、-h
の GNU 実装からの非標準の拡張ですdu
)。
しかし、これによって新たな問題が発生します。制限を回避するために複数回xargs
実行されますが、複数の行が生成され、複数回ハードリンクされたファイルのディスク使用量が複数回カウントされる可能性があります。du
execve()
total
のおかげで-r
、ファイルが見つからないdu
場合は は実行されませんlocate
が、それは行も取得されないことも意味します0 total
。
GNU の最近のバージョンではdu
、これらの問題は次のようにして解決できます。
locate -0 '*.doc' | du --files0-from=- -hc
今回は、ファイルのリストは引数ではなくパイプ経由で渡されるため、引数のサイズに制限はありません。また、そのリストを保存するために大量のメモリを割り当てる必要がなく、出力を開始するdu
とすぐに作業を開始できますlocate
。