Come fare in modo che xargs gestisca spazi e caratteri speciali da cat?


9

Ho un fileche contiene un elenco di nomi. vale a dire:

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

con spazi e alcuni personaggi speciali. Volevo creare directory con questi nomi, cioè:

cat file | xargs -l1 mkdir

Rende singole directory separate da spazi, cioè Long, Name, One, Two, Three, anziché Long Name One (001), Long Name Two (201), Long Name Three (123).

Come lo posso fare?

Risposte:


13

Usa -d '\n'con il tuo xargscomando:

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

Dalla manpage:

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

Esempio di output:

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

Per l' -dopzione sono necessari xarg GNU .
cuonglm,

@cuonglm Penso che principalmente abbia trovato GNU xargs. Ho anche controllato 1 , 2 , 3 . sì, potrebbe essere BSD
Pandya,


3

xargs si aspetta un formato di input molto speciale in cui gli argomenti sono delimitati da spazi vuoti o newline (a volte altre forme di spazi bianchi verticali, a volte dipendenti dalla locale corrente), e dove è possibile usare una virgoletta singola, virgolette doppie e una barra rovesciata (ma in un modo diverso dalle citazioni di shell).

-l1non è passare una riga di input come un singolo argomento a mkdir, ma chiamare una chiamata mkdirper ogni singola riga di input ma con parole su quella riga ancora separate come argomenti diversi mkdir.

L'implementazione GNU ha xargsaggiunto -0un'opzione decenni fa per accettare input delimitati da NUL. Questo è il modo più ovvio per separare le parole che finiranno per essere argomenti di un comando perché il carattere NUL è l'unico carattere che non può comparire in un argomento di comando o in un nome di file (il formato dell'elenco scelto che inserisce un file per riga non può rappresentare tutti i nomi file possibili in quanto non consente una nuova riga in un nome file).

Questo -0è stato copiato da molte altre xargsimplementazioni, ma non da tutte.

Con quelli che puoi fare:

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

Ciò chiamerà il mkdirminor numero di volte possibile con il maggior numero di argomenti possibile.

Ma nota che se fileè vuoto, mkdirverrà comunque eseguito e otterrai un errore di sintassi a mkdircausa dell'argomento mancante. GNU ha xargsaggiunto -run'opzione per ciò che è stato copiato da alcune altre implementazioni.

GNU ha xargsanche aggiunto (in seguito) -dun'opzione per poter specificare delimitatori arbitrari, ma non credo che nessun'altra implementazione lo abbia copiato. Con GNU xargs, il modo migliore è con:

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

Passando il file con -a(anche un'estensione GNU) invece di stdin, ciò significa che lo mkdirstdin viene preservato.

POSIX, dovresti post-elaborare l'input per metterlo nel formato previsto da xargs. Potresti farlo ad esempio con:

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

Dove racchiudiamo ogni riga tra virgolette doppie e fuggiamo da ciascuna "come "\""prima di alimentare xargs.

Ma attenzione alle possibili limitazioni:

  • l'errore quando il file è vuoto già menzionato sopra
  • potrebbe non riuscire con alcune implementazioni (incluso di sed) se il contenuto di filenon è un testo valido nella locale corrente. Se filecontiene nomi di file che codificano in più di un set di caratteri diverso o un set di caratteri diverso da quello della locale, è possibile correggere la locale su C, che dovrebbe essere d'aiuto.
  • alcune xargsimplementazioni hanno limiti ridicolmente bassi sulla lunghezza massima di un argomento (possono arrivare a 255 byte).

Per aggirare l' errore di sintassi in caso di errore di input vuoto , è possibile scrivere:

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

1

Rendi i nomi null terminati e suddividi lì:

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

trsostituirà la nuova riga catcon l'output \0, e i -0flag in xargsstanno dicendo di dividere gli argomenti su \0.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.