xargs - aggiunge ogni argomento con un parametro


12

So che, dato l="a b c",

echo $l | xargs ls

i rendimenti

ls a b c

Quale costrutto produce

mycommand -f a -f b -f c

Risposte:


13

Un modo per farlo:

echo "a b c" | xargs printf -- '-f %s\n' | xargs mycommand

Ciò presuppone a, be cnon contengono spazi vuoti, a capo, virgolette o backslash. :)

Con GNU findutilpuoi gestire il caso generale, ma è leggermente più complicato:

echo -n "a|b|c" | tr \| \\0 | xargs -0 printf -- '-f\0%s\0' | xargs -0 mycommand

È possibile sostituire il |separatore con qualche altro personaggio, che non figura in a, bo c.

Modifica: Come osserva @MichaelMol , con un elenco molto lungo di argomenti c'è il rischio di traboccare la lunghezza massima degli argomenti a cui è possibile passare mycommand. Quando ciò accade, l'ultimo xargsdivide l'elenco e ne esegue un'altra copia mycommand, e c'è il rischio che rimanga non terminato -f. Se ti preoccupi di quella situazione, potresti sostituire l'ultimo xargs -0sopra con qualcosa del genere:

... | xargs -x -0 mycommand

Questo non risolverà il problema, ma si interromperà mycommandquando l'elenco degli argomenti diventa troppo lungo.


1
Corri un brutto rischio di superare ARG_MAXe avere un -fparametro separato dal suo parametro associato.
Michael Mol,

@MichaelMol Questo è un buon punto, ma non credo che ci sia un modo significativo per gestire quella situazione senza saperne di più mycommand. Puoi sempre aggiungere -xl'ultimo xargs.
Satō Katsura,

Penso che la soluzione corretta sia probabilmente non usare xargsaffatto, e usare solo findse può essere usata. Questa soluzione è pericolosa; dovresti almeno avvisare del caso di fallimento nella tua risposta.
Michael Mol,

@MichaelMol Non vedo davvero come findsarebbe una soluzione generale migliore, in particolare quando gli argomenti iniziali non sono nomi di file. :)
Satō Katsura,

Non sappiamo quali siano gli argomenti iniziali; vediamo solo l'esempio fornito, non lo scenario che ha ispirato la domanda. L'intuizione suggerisce che con un argomento chiamato -fe con uno strumento di esempio lsusato per l'illustrazione, @ non-un-utente ha a che fare con nomi di file. E dato findoffre l' -execargomento, che ti permette di costruire una riga di comando, va bene. (Finché mycommandè consentito eseguire più di una volta. In caso contrario, abbiamo un altro problema con l'uso di xargsqui ...)
Michael Mol

5

Un modo migliore per affrontarlo (IMO) sarebbe:

  • in zsh:

    l=(a b c)
    mycommand -f$^l

    o usando l'array zipping in modo che l'argomento non sia associato all'opzione:

    l=(a b c) o=(-f)
    mycommand "${o:^^l}"

    In questo modo, funziona ancora se l' larray contiene elementi vuoti o elementi contenenti spazi o qualsiasi altro carattere problematico per xargs. Esempio:

    $ l=(a '' '"' 'x y' c) o=(-f)
    $ printf '<%s>\n' "${o:^^l}"
    <-f>
    <a>
    <-f>
    <>
    <-f>
    <">
    <-f>
    <x y>
    <-f>
    <c>
  • in rc:

    l=(a b c)
    mycommand -f$l
  • in fish:

    set l a b c
    mycommand -f$l

(AFAIK rce fishnon ha zippatura di array)

Con gusci di tipo Bourne vecchio stile come bash, potresti sempre fare (permettendo comunque qualsiasi carattere negli elementi $@dell'array):

set -- a b c
for i do set -- "$@" -f "$i"; shift; done
mycommand "$@"

1
Un altro modo per farlo in bash è con una variabile array denominata. for i; do args+=('-f' "$i");done; mycommand "${args[@]}". IDK se questo è più veloce, ma l'aggiunta di 2 elementi a un array sembra che dovrebbe essere O (n), mentre il tuo setloop probabilmente copia e analizza nuovamente l'elenco arg accumulato ogni volta (O (n ^ 2)).
Peter Cordes,
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.