如何让 xargs 处理空格和特殊字符?

如何让 xargs 处理空格和特殊字符?

我有一个file包含姓名列表的列表。 IE:

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

带有空格和一些特殊字符。我想用这些名称创建目录,即:

cat file | xargs -l1 mkdir

它使各个目录用空格分隔,即Long, Name, One, Two, Three, 而不是 Long 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

POSIXly:

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

(请注意,while在 shell 脚本中使用循环处理文本被认为是不好的做法)

答案3

xargs需要一种非常特殊的输入格式,其中参数由空格或换行符分隔(有时是其他形式的垂直空格,有时取决于当前区域设置),并且可以使用单引号、双引号和反斜杠来转义它们(但在不同的情况下)来自 shell 引号的方式)。

-l1不是将一行输入作为单个参数传递给mkdir,而是mkdir为每一行输入调用一次调用,但该行上的单词仍然作为不同的参数分离出来mkdir

几十年前的GNU 实现xargs添加了一个-0选项来接受 NUL 分隔的输入。这是分隔最终将成为命令参数的单词的最明显方法,因为 NUL 字符恰好是命令参数或文件名中不能出现的唯一字符(您选择的列表格式每行放置一个文件)无法表示所有可能的文件名,因为它不允许文件名中出现换行符)。

-0已被其他几个实现复制,xargs但不是全部。

有了这些你可以做:

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

这将调用mkdir尽可能少的次数和尽可能多的参数。

但请注意,如果file为空,仍然会运行,并且由于缺少参数,mkdir您会收到语法错误。 mkdirGNUxargs添加了一个-r选项,该选项已被其他一些实现复制。

GNUxargs还添加了(后来)一个-d能够指定任意分隔符的选项,但我不认为任何其他实现会复制它。对于 GNU xargs,最好的方法是:

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

-a通过使用(也是 GNU 扩展名)而不是 stdin传递文件,这意味着mkdir的 stdin 被保留。

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

相关内容