
find
このコマンドは、ファイル名をnullで区切られた文字列(提供されている-print0
場合)として出力することができ、オプションがオンの状態で使用できますxargs
。-0
しかし、その間には、対応するファイルのコレクションを操作することは困難です。sort
コマンドには-z
ファイルを並べ替えるスイッチがありますが、head
含まれていませんtail
。
これらのnullで区切られた入力を便利な方法でどのようにhead
ANDできますか?tail
(いつでも短くて遅いRubyスクリプトを作成できますが、より良い方法があることを願っています)
答え1
GNUhead
およびtail
coreutilsバージョン8.25以降の-z
オプションがあります。
以前のバージョンまたはGNU以外のシステムでは、次のように\0
交換してみることができます\n
。
find ... -print0 |
tr '\0\n' '\n\0' |
head |
tr '\0\n' '\n\0'
一部のhead
実装ではNUL文字を処理できませんが(POSIXではこれを必要としません)、findは処理し、テキスト-print0
ユーティリティhead
は通常NUL文字をサポートします。
tr
関数を使用して2つの間のコマンドをラップすることもできます。
nul_terminated() {
tr '\0\n' '\n\0' | "$@" | tr '\0\n' '\n\0'
}
find ... -print0 | nul_terminated tail -n 12 | xargs -r0 ...
下のnul_terminated
aは\0
改行文字を表します。たとえば、\n
次のように変更します_
。
find . -depth -name $'*\n*' -print0 | nul_terminated sed '
p;h;s,.*/,,;s/\x0/_/g;H;g;s,[^/]*\n,,' | xargs -r0n2 mv
(\x0
また、GNU拡張)。
複数を実行する必要がある場合フィルターコマンドを使用すると、次のことができます。
find ... -print0 |
nul_terminated cmd1 |
nul_terminated cmd2 | xargs -r0 ...
ただし、これはいくつかの冗長tr
コマンドを実行することを意味します。または、以下を実行できます。
find ... -print0 | nul_terminated eval 'cmd1 | cmd2' | xargs -r0 ...
答え2
以前のシステムでは、nullで区切られた入力がサポートされていたため、grep
3つの最新のファイルをインポートする代わりにこれを実行しました。head --zero-terminated -n 3
find . -maxdepth 1 -type f -printf "%T@ %p\0" | sort -zrn | grep -zm 3 ""
sort
との組み合わせを使用すると、grep
置き換えによってtail
3番目の最新のファイルを取得できます。
find . -maxdepth 1 -type f -printf "%T@ %p\0" | sort -zrn | grep -zm 3 "" | sort -zn | grep -zm 1 ""
ファイル名のみ:
find . -maxdepth 1 -type f -printf "%T@ %p\0" | sort -zrn | grep -zm 3 "" | sort -zn | grep -zPom 1 "(?s)/.*"
残念ながら、-o
(一致のみ)ゼロで区切られた出力(バグ!?)を無効にします。これは次のようにアクティブになり、末尾の改行を含む-z
ファイル名を返すため、追加のパイピングは許可されません。
find . -maxdepth 1 -type f -printf "%T@ %p\0" | sort -zrn | grep -zm 3 "" | sort -zn | grep -zPom 1 "(?s)/.*" | xargs -0 ls -l
ls: cannot access /te
st
: No such file or directory
この問題は、以下を使用して解決できますread
。
find . -mindepth 1 -maxdepth 1 -type f -printf "%T@ %p\0" | sort -zrn | grep -zm 3 "" | sort -zn | { IFS=" " read -rd '' mtime file && echo -en "$file\0"; } | xargs -0 -n1 ls -l
-rw-r--r-- 1 root root 0 Apr 24 17:46 ./te?st
(ls -t
予想通り、ファイル名の改行文字の疑問符を返します。)
または、現在のディレクトリから最も古い100ファイルをインポートする方法の別の例は次のとおりです。
find /tmp/test -mindepth 1 -maxdepth 1 -type f -printf "%T@ %p\0" | sort -zn | grep -zm 10 "" | { while IFS=" " read -rd '' mtime file; do echo -en "$file\0"; done; } | xargs -0 -n1 ls -bl
-rw-r--r-- 1 root root 0 Mar 23 14:32 /tmp/test/foo\ baz.txt
-rw-r--r-- 1 root root 0 Apr 26 10:43 /tmp/test/foo\nbar\ baz.txt
...