Como fazer xargs manipular espaços e caracteres especiais do gato?

9

Eu tenho um fileque contém uma lista de nomes. ou seja:

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

com espaços e alguns caracteres especiais. Eu queria criar diretórios com esses nomes, ou seja:

cat file | xargs -l1 mkdir

Faz directórios individuais separadas por espaços, isto é Long, Name, One, Two, Three, em vez de Long Name One (001), Long Name Two (201), Long Name Three (123).

Como eu posso fazer isso?

Majal
fonte

Respostas:

13

Use -d '\n'com seu xargscomando:

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

Da página de manual:

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

Exemplo de saída:

$ 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)
Pandya
fonte
Você precisa do GNU xargs para a -dopção.
precisa saber é
@cuonglm Acho que encontrei principalmente xargs GNU. Eu também verifiquei 1 , 2 , 3 . sim BSD pode ser caso
Pandya
3

xargs espera um formato de entrada muito especial em que os argumentos sejam delimitados por espaços em branco ou novas linhas (às vezes outras formas de espaço em branco vertical, às vezes dependentes da localidade atual) e onde aspas simples, aspas duplas e barra invertida podem ser usadas para evitá-las (mas de uma maneira diferente caminho de aspas shell).

-l1não é passar uma linha de entrada como um único argumento para mkdir, mas chamar uma mkdirchamada para cada linha de entrada, mas com palavras nessa linha ainda separadas por argumentos diferentes para mkdir.

A implementação do GNU xargsadicionou uma -0opção décadas atrás para aceitar dados delimitados por NUL. Essa é a maneira mais óbvia de separar palavras que acabarão sendo argumentos para um comando, porque o caractere NUL passa a ser o único caractere que não pode ocorrer em um argumento de comando ou nome de arquivo (o formato de lista escolhido que coloca um arquivo por linha não pode representar todos os nomes de arquivos possíveis, pois não permite uma nova linha em um nome de arquivo).

Isso -0foi copiado por várias outras xargsimplementações, mas não por todas.

Com aqueles que você pode fazer:

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

Isso chamará o menor mkdirnúmero de vezes possível com o maior número de argumentos possível.

Mas observe que, se fileestiver vazio, mkdirainda será executado e você receberá um erro de sintaxe mkdirdevido ao argumento ausente. O GNU xargsadicionou uma -ropção para o que foi copiado por algumas outras implementações.

O GNU xargstambém adicionou (mais tarde) uma -dopção para poder especificar delimitadores arbitrários, mas acho que nenhuma outra implementação o copiou. Com o GNU xargs, a melhor maneira é:

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

Ao passar o arquivo com -a(também uma extensão GNU) em vez de stdin, isso significa que mkdiro stdin é preservado.

POSIX, você precisaria pós-processar a entrada para colocá-la no formato esperado por xargs. Você poderia fazê-lo, por exemplo, com:

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

Onde colocar cada linha dentro de aspas e escapar cada "como "\""antes de alimentar a xargs.

Mas cuidado com as possíveis limitações:

  • o erro quando o arquivo está vazio já mencionado acima
  • pode falhar em algumas implementações (inclusive de sed) se o conteúdo de filenão for um texto válido no código do idioma atual. Se filecontiver nomes de arquivos codificados em mais de um conjunto de caracteres diferente, ou um conjunto de caracteres diferente daquele do código de idioma, será possível corrigir o código de idioma em C, o que deve ajudar.
  • algumas xargsimplementações têm limites ridiculamente baixos no tamanho máximo de um argumento (pode ser tão baixo quanto 255 bytes).

Para contornar o erro de sintaxe após um erro de entrada vazio , você pode escrever:

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

Torne os nomes nulos terminados e divida lá:

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

trsubstituirá a nova linha catcom a saída \0e os -0sinalizadores in xargsestão dizendo para ele dividir argumentos no \0.

Kira
fonte
1

Você pode fazer isso POSIXLY com a -Iopção:

xargs -I % mkdir % < file

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

Steven Penny
fonte
Embora funcione com a amostra do OP, você ainda terá problemas com espaços em branco à esquerda, aspas simples, aspas duplas e barras invertidas (e possivelmente linhas longas e sequências de bytes que não formam caracteres válidos no código do idioma).
Stéphane Chazelas