xargsにスペースと特殊文字を処理させる方法は?

xargsにスペースと特殊文字を処理させる方法は?

file名前のリストを含むリストがあります。つまり:

Long Name One (001)
Long Name Two (201)
Long Name Three (123)
...

スペースといくつかの特殊文字が含まれています。次の名前でディレクトリを作成したいと思います。

cat file | xargs -l1 mkdir

これにより、ディレクトリがスペースで区切られます(たとえば、、、Long代わりNameOne、、、、、Twoなど)。ThreeLong Name One (001)Long Name Two (201)Long Name Three (123)

どうすればいいですか?

答え1

使用-d '\n'あなたのコマンドでxargs

cat file | xargs -d '\n' -l1 mkdir

マンページから:

-d delim
              Input  items  are  terminated  by the specified character.  Quotes and backslash are not special; every
              character in the input is taken literally.  Disables the end-of-file string, which is treated like  any
              other  argument.   This can be used when the input consists of simply newline-separated items, although
              it is almost always better to design your program to use --null where this is possible.  The  specified
              delimiter  may be a single character, a C-style character escape such as \n, or an octal or hexadecimal
              escape code.  Octal and hexadecimal escape codes are understood as for the printf command.    Multibyte
              characters are not supported.

出力例:

$ ls
file

$ cat file
Long Name One (001)
Long Name Two (201)
Long Name Three (123)

$ cat file | xargs -d '\n' -l1 mkdir

$ ls -1
file
Long Name One (001)
Long Name Three (123)
Long Name Two (201)

答え2

xargsの実装が-0オプションをサポートしている場合:

tr '\n' '\0' <file | xargs -0 -l1 mkdir

POSIX的に:

while IFS= read -r file; do
  mkdir -p -- "$file"
done <file

whileシェルスクリプトでテキストを処理するためにループを使用することは悪い習慣と見なされます。)

答え3

xargs非常に特別な入力フォーマットが必要です。ここでは、引数はスペースまたは改行(現在のロケールによって異なる形式の垂直スペース)で区切られ、単一引用符、二重引用符、およびバックスラッシュを使用してエスケープできます(ただしシェル引用符とは異なる方法)。

-l1入力行を単一の引数として渡すのではなく、各入力行に対して呼び出しが行われますが、その行mkdirmkdir単語はまだ一意の引数に分割されますmkdir

数十年前のGNU実装には、NULで区切られた入力を許可するオプションがxargs追加されました。-0これは最終的にコマンド引数になる単語を分離する最も確実な方法です。なぜなら、NUL文字はコマンド引数またはファイル名(選択したリスト形式では1行に1つのファイルを入力する)には現れない唯一の文字であるからです。ファイル名に改行文字を許可しないため、すべての可能なファイル名を示します。

これは-0いくつかの異なる実装によってコピーされましたが、xargsすべてではありません。

これにより、次のことができます。

<file tr '\n' '\0' | xargs -0 mkdir -p --

mkdirこれは、できるだけ多くの引数を使用してできるだけ少ない回数で呼び出されます。

ただし、file空の場合は引き続き実行され、パラメータの欠落mkdirにより構文エラーが発生します。mkdirGNUは他の実装によってコピーされたオプションをxargs追加しました。-r

GNUはxargs(後で)-d任意の区切り文字を指定するオプションも追加しましたが、他の実装ではそれを複製できないようです。 GNUの場合、xargs最良のアプローチは次のとおりです。

xargs -rd '\n' -a file mkdir -p --

-astdinの代わりにGNU拡張子を使用してファイルを渡すと、mkdirstdinが保存されます。

POSIXlyでは、入力を後処理してxargs

<file sed 's/"/"\\""/g; s/^/"/; s/$/"/' | xargs mkdir -p --

"xargsを入力する前に行ったように、各行を二重引用符で囲み、各行をエスケープします"\""

ただし、考えられる制限に注意してください。

  • ファイルが空の場合に発生するエラーは上記のとおりです。
  • sedの内容がfile現在のロケールで有効なテキストではない場合、一部の実装(含む)が失敗する可能性があります。複数の異なる文字セットでエンコードされたファイル名が含まれている場合、またはロケールと他の文字セットが含まれている場合は、fileロケールをCに変更すると便利です。
  • 一部のxargs実装では、パラメータの最大長に対する制限は非常に低くなります(255バイトほど低い場合があります)。

空の入力時の構文エラーエラーは次のように書くことができます。

<file sed 's/"/"\\""/g; s/^/"/; s/$/"/' |
  xargs sh -c '[ "$#" -eq 0 ] || exec mkdir -p -- "$@"' sh

答え4

次のオプションを使用して、POSIXLYでこれを実行できます-I

xargs -I % mkdir % < file

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/xargs.html

関連情報