xargsからパイプ出力を正しくエスケープします。

xargsからパイプ出力を正しくエスケープします。

例:

% 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 | xargsa

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

これはaandbファイルでも、名前というファイルでもかまいませんa<newline>b。知る方法はありません。

GNUには出力を明確にし、後処理するls機能がありますが、引用は予想される引用と互換性がありません。識別と引用フォーム。ただし、andは両方とも強い引用符であり、改行文字を含めることはできません(改行文字のみエスケープできます)。したがって、強い引用符のみがあり、改行文字を含めることができますが、エスケープの代わりに行の連続(削除)を持つs​​h引用符と互換性がありません。改行文字。--quoting-style=shell-alwaysxargsxargs"..."\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'

おすすめ記事