人間が読めるパスのリストを別のコマンドにリダイレクトする方法は?

人間が読めるパスのリストを別のコマンドにリダイレクトする方法は?

locate「人が読める形式」(つまり、先行スペースなし)でパスリストを生成するコマンド出力など、コマンド出力を使用するときに出力を別のコマンド\にリダイレクトするにはどうすればよいですか。

の出力は$ locate [something]スペースを含むパスを生成するため、他のプログラムはスペースを含むパスを使用できません。たとえば、

$ du -h `locate *.doc`

これにより、スペースを含むすべてのファイルとディレクトリにエラーが発生します。 (空白でチックを包むことは機能しません)

答え1

それを使用する具体的な理由は何ですかlocate?これはあなたの要件を満たすようです。

find . -type f -name '*doc' -exec du -h "{}" \;

つまり、本物locateあるいは、同じツールを使用してその入力を別のプログラムに引数として渡したい場合は、一部のツールが提供する別々の出力と入力を find利用できます。そして、両方とも読み取り用に設計されたよりプログラム的に使いやすい出力を得るためのオプション( 'sと's )があります。NULlocatefindlocate-0find-print0xargsそれ -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などのシェル(zshでのみ分割)でSplit + globを呼び出します。

デフォルトでは、分割は$IFSスペース、タブ、および改行(zshではNUL)の特殊パラメータを含む文字に対して行われます。これは、空白文字を含むファイル名でコマンドが機能しない理由を説明します。

次のことができます。

(IFS='
' # split on newline only
set -o noglob # disable glob
du -hc -- $(locate '*.doc'))

ただし、ファイル名に改行文字が含まれている場合はまだ失敗します。出力はlocateまったく後処理できません。

ほとんどの実装にはファイルパスを区別して出力するオプションがlocateあります。 NULは、ファイルパスには現れない唯一のバイト値です。つまり、出力が後処理可能であることを意味します。 NULに分割するだけです。-0NUL

存在する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つの質問が残っています。

  1. locateファイルが見つからない場合は、du -hc --引数なしで実行されます。つまり、現在の作業ディレクトリのディスク使用量がわかります。
  2. 一方、locate多くのファイルが見つかると、最終的にシステムコールの制限に達し、execve()エラーが発生する可能性があります。引数のリストが長すぎます。間違い。

以下を行うと、これらの問題をすべて回避できます。

locate -0 '*.doc' | xargs -r0 du -hc --

-rそして-0GNU実装の非標準拡張xargsと同様に、-hGNU実装の非標準拡張ですdu。)

しかし、これは新しい問題を引き起こします。制限を解決するために複数回xargs実行されますが、これはいくつかの行を取得し、複数回ハードリンクされたファイルのディスク使用量が複数回計算されることを意味します。duexecve()total

ありがとうございます-r。ファイルがないとdu実行されません。しかし、これは1行も表示されないという意味でもあります。locate0 total

最新バージョンのGNUを使用すると、次duの方法でこれらの問題を解決できます。

locate -0 '*.doc' | du --files0-from=- -hc

今回はパラメータの代わりにパイプを介してファイルのリストを渡すため、パラメータのサイズに制限はありません。これはまた、リストを格納するために多くのメモリを割り当てる必要がなく、出力を開始するduとすぐにlocate処理を開始できることを意味します。

関連情報