例:
% touch -- safe-name -name-with-dash-prefix "name with space" \
'name-with-double-quote"' "name-with-single-quote'" \
'name-with-backslash\'
xargs
二重引用符を処理できないようです。
% ls | xargs ls -l
xargs: unmatched double quote; by default quotes are special to xargs unless you use the -0 option
ls: invalid option -- 'e'
Try 'ls --help' for more information.
このオプションを使用すると、-0
名前の前にダッシュが付くと問題が発生します。
% ls -- * | xargs -0 -- ls -l --
ls: invalid option -- 'e'
Try 'ls --help' for more information.
改行文字、制御文字など、潜在的に問題のある他の文字を使用する前です。
答え1
これPOSIX仕様あなたに例を与える:
ls | sed -e 's/"/"\\""/g' -e 's/.*/"&"/' | xargs -E '' printf '<%s>\n'
(ファイル名はランダムな順序です。バイト( /
NULLを除く)およびsed
/xargs
期待テキスト、信頼できるようにロケールをC(NUL以外のすべてのバイトが有効な文字を生成する場合)に変更する必要があります(xargs
引数の最大長の制限が非常に低い実装を除く)。
-E ''
一部の実装では、入力の終わり(出力のみ)を表す引数をxargs
理解する必要があります。_
echo a _ b | xargs
a
GNUでは、xargs
次のことができます。
ls | xargs -rd '\n' printf '<%s>\n'
(また、追加された-r
(またGNU拡張)は、入力が空の場合、コマンドは実行されないことです。)
GNUには他の実装によってコピーされたxargs
ものもあるので、次のようになります。-0
ls | tr '\n' '\0' | xargs -0 printf '<%s>\n'
携帯性が少し良くなりました。
これらすべては、ファイル名に改行文字が含まれていないと仮定します。ファイル名に改行がある場合、出力はls
まったく後処理されません。あなたが得る場合:
a
b
これはa
andb
ファイルでも、名前というファイルでもかまいませんa<newline>b
。知る方法はありません。
GNUには出力を明確にし、後処理するls
機能がありますが、引用は予想される引用と互換性がありません。識別と引用フォーム。ただし、andは両方とも強い引用符であり、改行文字を含めることはできません(改行文字のみエスケープできます)。したがって、強い引用符のみがあり、改行文字を含めることができますが、エスケープの代わりに行の連続(削除)を持つsh引用符と互換性がありません。改行文字。--quoting-style=shell-always
xargs
xargs
"..."
\x
'...'
"..."
'...'
\
xargs
'...'
\<newline>
シェルを使用してこの出力を解析し、予想される形式で出力できますxargs
。
eval "files=($(ls --quoting-style=shell-always))"
[ "${#files[@]}" -eq 0 ] || printf '%s\0' "${files[@]}" |
xargs -0 printf '<%s>\n'
あるいは、シェルにファイルのリストをインポートし、NULで区切って渡すこともできますxargs
。たとえば、次のようになります。
そして
zsh
:print -rNC1 -- *(N) | xargs -r0 printf '<%s>\n'
そして
ksh93
:(set -- ~(N)*; (($# == 0)) || printf '%s\0' "$@") | xargs -r0 printf '<%s>\n'
そして
fish
:begin set -l files *; string join0 -- $files; end | xargs -r0 printf '<%s>\n'
そして
bash
:( shopt -s nullglob set -- * (($# == 0)) || printf '%s\0' "$@" ) | xargs -r0 printf '<%s>\n'
2023年編集。 GNU coreutilsバージョン9.0(2021年9月)以降、GNUにはls
次--zero
のコマンドで使用できるオプションがありますxargs -r0
。
ls --zero | xargs -r0 printf '<%s>\n'
答え2
xargs
null で区切られた入力オプションを理解するには、-0
送信者は送信データに null 区切り文字も適用する必要があります。
それ以外の場合、2 つの間で同期は発生しません。
1つのオプションは、GNU find
これらの区切り文字を配置できるコマンドです。
find . -maxdepth 1 ! -name . -print0 | xargs -0 ls -ld
答え3
あなたが言ったようにをxargs
使用しない限り、一致しない二重引用符が好きではありません。-0
しかし、-0
これはnullで終わるデータを入力する場合にのみ意味があります。したがって、これは失敗します。
$ echo * | xargs
xargs: unmatched double quote; by default quotes are special to xargs unless you use the -0 option
name-with-backslash -name-with-dash-prefix
しかし、これはうまくいきます:
$ printf '%s\0' -- * | xargs -0
-- name-with-backslash\ -name-with-dash-prefix name-with-double-quote" name-with-single-quote' name with space safe-name
とにかく、基本的なアプローチは実際にこれを行う最善の方法ではありません。xargs
and とls
そのようなものを操作する代わりに、シェルグロブを使用してください。
$ for f in *; do ls -l -- "$f"; done
-rw-r--r-- 1 terdon terdon 4142 Aug 11 16:03 a
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 'name-with-backslash\'
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 -name-with-dash-prefix
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 'name-with-double-quote"'
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 "name-with-single-quote'"
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 'name with space'
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 safe-name
答え4
これを試すのはとても愚かなことですコマンドの出力を解析します。ls
それは解析用に設計されていない命令を出す複数の文字を処理するのに適していません(例:new lines
および{}
)シェルがそれ自体でこれを行う場合:
set -- *; for f; do echo "<$f>"; done
set -- *
for f
do ls "$f"
done
または、コマンドラインで次の操作を行います。
$ set -- *; for f; do echo "<$f>"; done
<name-with-backslash\>
<-name-with-dash-prefix>
<name-with-double-quote">
<name-with-single-quote'>
<name with space>
<safe-name>
<with_a
newline>
出力処理(そして最後のファイル名としてn個の例を持つもの)は改行にまったく問題がないことに注意してください。
または、ファイルの数によってシェルが遅くなる場合は、findを使用してください。
$ find ./ -type f -exec echo '<{}>' \;
<./safe-name>
<./with_a
newline>
<./name-with-double-quote">
<./-name-with-dash-prefix>
<./name with space>
<./name-with-single-quote'>
<./name-with-backslash\>
findはシェルとは異なり、すべてのドットファイルとすべてのサブディレクトリを処理します。