Come assegnare un elenco separato da virgole come argomenti al comando successivo


9

Ho uno script s1che genera un elenco di numeri separati da ',' ad es 1,2,3,4. Ora voglio dare questi numeri allo script s2come argomenti, in modo che s2 venga eseguito su ciascuno di essi e ne generi il risultato in una riga separata. Ad esempio, se s2 moltiplica i numeri per due, questo sarebbe il risultato che sto cercando:

2
4
6
8

Quello che sto facendo in questo momento è:

s1 | xargs -d "," | xargs -n1 s2

Ma mi sento di farlo in un modo così sciocco! Quindi la mia domanda è:

Qual è il modo corretto di farlo?

Il mio problema con la mia soluzione è che sta chiamando xargs due volte e iterando sull'input due volte, il che non è ragionevole per i miei occhi ovviamente per mezzo delle prestazioni! La risposta xargs -d "," -n1sembra carina, ma non sono sicuro che stia iterando solo una volta. In tal caso, verificalo nella tua risposta e lo accetterò. A proposito, preferirei non usare Perl poiché sta ancora ripetendo due volte e anche Perl potrebbe non esistere su molti sistemi.


1
Se funziona, perché chiamarlo sciocco. Se i tempi di esecuzione sono importanti, allora è un'altra cosa che
resta

2
Prova questos1 | xargs -d "," -n1 s2
George Udosen il

1
Sospetto che parte del problema stia fraintendendo l'impatto dell'iterazione. Iterare gli elementi in qualcosa di simile a un array associativo è male a causa delle spese per camminare su quella struttura di dati, ma "iterare" in generale non è intrinsecamente negativo. In particolare, leggere i dati riga per riga quando arrivano su STDIN, non è un grosso problema di prestazioni. Il problema delle prestazioni qui è più il costo di generare un nuovo processo e impostare la pipeline. Finché non lo fai frequentemente (come in un ciclo), preoccuparsi delle prestazioni di xargs è probabilmente un esempio di ottimizzazione prematura.
dannysauer,

Risposte:


18

Anche questo dovrebbe funzionare allo stesso modo:

s1 | xargs -d "," -n1 s2

Caso di prova:

printf 1,2,3,4 | xargs -d ',' -n1 echo

Risultato:

1
2
3
4

Se l' s1output di quell'elenco è seguito da un carattere di nuova riga, ti consigliamo di rimuoverlo, altrimenti sarebbe l'ultima chiamata 4\ninvece di 4:

s1 | tr -d '\n' | xargs -d , -n1 s2

6

Se s2puoi accettare più argomenti, puoi fare:

(IFS=,; ./s2 $(./s1))

che sostituisce temporaneamente IFS come una virgola, tutto in una subshell, in modo da s2vedere l'output di s1scomposto per virgole. La subshell è un modo breve per modificare IFS senza salvare il valore precedente o ripristinarlo.

Una versione precedente di questa risposta era errata, probabilmente a causa di un'impostazione IFS rimanente, corrompendo i risultati. Grazie a ilkkachu per aver segnalato il mio errore .

Per eseguire manualmente il loop over delle uscite e fornirle individualmente s2, qui dimostrando il salvataggio e il ripristino di IFS:

oIFS="$IFS"
IFS=,
for output in $(./s1); do ./s2 "$output"; done
IFS="$oIFS"

oppure esegui i bit IFS in una subshell come prima:

(
IFS=,
for output in $(./s1); do ./s2 "$output"; done
)

1
Ne sei sicuro? bash -c 'IFS=, printf "%s\n" $(echo 1,2,3)'stampa 1,2,3sul mio sistema, cioè non c'è divisione.
ilkkachu,

Proverò di nuovo tra un po ', ma sospetto comportamenti diversi basati su programmi integrati o esterni.
Jeff Schaller

lo stesso con /usr/bin/printfe/bin/echo
ilkkachu il

1
@ilkkachu Hai ragione, la divisione delle parole si verifica prima che l'IFS venga riassegnato in questo caso (IFS=,; printf "%s\n" $(echo 1,2,3)), d'altra parte, dovrebbe funzionare.
undercat applaude Monica il

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.