如何使xargs处理cat中的空格和特殊字符?


9

我有一个file包含名称列表的列表。即:

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

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

cat file | xargs -l1 mkdir

它使用空格分隔各个目录,即LongNameOneTwoThree,而不是 Long Name One (001)Long Name Two (201)Long Name Three (123)

我怎样才能做到这一点?

Answers:


13

-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)

您需要GNU xargs作为-d选项。
cuonglm '16

@cuonglm我认为主要是找到了GNU xargs。我也查了123。是的,BSD可能就是这种情况
Pandya


3

xargs 需要一种非常特殊的输入格式,其中参数由空格或换行符分隔(有时其他形式的垂直空白,有时取决于当前的语言环境),并且单引号,双引号和反斜杠可用于转义(但可以使用不同的从外壳引号的方式)。

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

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

-0已经被其他几种xargs实现复制了,但还不是全部。

通过这些,您可以执行以下操作:

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

这将mkdir使用尽可能多的参数调用尽可能少的时间。

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

GNU xargs还(稍后)添加了一个-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

1

使名称以null终止并在此处拆分:

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

tr将会用替换cat输出的换行符\0,并且其中的-0标志xargs告诉它在上拆分参数\0


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.