Utilizzo di xargs in combinazione con bash -c per creare comandi complessi

Contenuti

xargs sono fuochi d'artificio per i comandi della shell. Qualsiasi via d'uscita, generato da qualsiasi comando di shell, può essere inviato a xargs per essere elaborato su un'altra riga di comando. Impara a sfruttare questo grande potere degli xarg oggi!!

Introduzione a xargs

Il mio collega Dave McKay ha scritto un post interessante Come usare il comando xargs in Linux, che ti potrebbe piacere leggere prima per un'introduzione dettagliata e un'esplorazione di xargs in generale.

Questo post si concentrerà su un ostacolo specifico: cosa fare quando si riscontrano limitazioni dell'impilamento tradizionale o normale basato su tubi (; delimitato) Comandi Linux, e quando anche l'uso di xargs non sembra fornire una risposta subito?

Questo è il caso frequente, si non frequente, quando si scrivono script a riga singola sulla riga di comando e / o quando si elaborano strutture dati o dati complessi. Le informazioni qui presentate si basano sulla ricerca e su molti anni di esperienza nell'utilizzo di questo particolare metodo e approccio..

Tubi e xargs

Chiunque impari Bash aumenterà nel tempo le proprie capacità di scripting da riga di comando.. La cosa grandiosa di Bash è che tutte le abilità apprese sulla riga di comando sono facilmente tradotte in script Bash. (che sono generalmente contrassegnati con a .sh suffisso). La sintassi è quasi identica.

E, man mano che le abilità migliorano, i nuovi ingegneri generalmente scopriranno prima il linguaggio Pipe. Usare una pipa è facile e immediato: l'output del comando precedente è' pipe’ all'input per il seguente comando, pensalo come un tubo dell'acqua che trasporta l'acqua da una fonte di uscita a una fonte di ingresso altrove, come esempio, acqua da una diga collegata a una turbina idraulica.

Vediamo un semplice esempio:

eco 'a' | sed 's/a/b/'

Un semplice esempio di pipeline Bash con sostituzione del testo regex sed

Qui abbiamo appena fatto eco 'a’ e in seguito cambiamo lo stesso usando l'editor del flusso di testo sed. L'output è naturalmente 'b': la sete sostituita (comando s) 'un’ una 'b'.

Qualche tempo dopo, l'ingegnere scoprirà che i tubi hanno ancora capacità limitate, soprattutto quando si desidera pre-elaborare i dati in un formato pronto per il prossimo strumento. Come esempio, considera questa situazione:

Affrontare sfide usando un tubo in combinazione con l'uccisione

Qui iniziamo un sogno profondo. Successivamente usiamo pidof per recuperare il PID del comando di sospensione in esecuzione e provare a rimuoverlo con kill -9 (Pensa a -9 come un modo distruttivo per uccidere una procedura). Non riesce. Quindi proviamo a utilizzare il PID fornito dalla shell quando avviamo la procedura in background, ma questo fallisce allo stesso modo.

Il problema è che kill non accetta input direttamente, se viene da ps o anche un semplice echo. Per risolvere questo problema, possiamo usare xargs per prendere l'output di ps o la echo comando) e fornirli come input per kill, rendendoli argomenti per il comando kill. È come se avessimo eseguito kill -9 some_pid In modo diretto. Vediamo come funziona:

dormire 300 &
pidof sonno | xargs kill -9

xargs risolve il problema del comando pipe kill visto sopra

Funziona alla grande e raggiunge ciò che ci eravamo prefissati di fare: uccidi la procedura del sonno. Un piccolo cambiamento nel codice (In altre parole, basta aggiungere xargs davanti al comando), Ma un grande cambiamento nell'utilità di Bash per l'ingegnere di sviluppo!!

Possiamo anche usare il -I opzione (che imposta l'argomento della stringa di sostituzione) un kill per spiegare un po' come stiamo passando argomenti per uccidere: i12b qui, noi definiamo {} come la nostra catena di sostituzione. In altre parole, finché xargs vede {}, lo sostituirà {} a qualsiasi input ricevuto dall'ultimo comando.

Comunque, anche questo ha i suoi limiti. E se volessimo fornire alcune buone informazioni di debug stampate online e dall'interno della dichiarazione?? Sembra impossibile finora.

sì, potremmo post-elaborare l'output con a sed regex, o inserisci un sottolivello ($()) in qualche posto, ma tutti questi sembrano ancora avere dei limiti, e soprattutto quando arriva il momento di creare flussi di dati complessi, senza usare un nuovo comando e senza usare file temporanei intermedi.

E se potessimo?, una volta per tutte, lasciati alle spalle questi limiti e sii 100% libero di creare alcuni La riga di comando bash che ci piace, usa solo tubi, xargs y el shell Bash, senza file intermedi temporanei e senza avviare un nuovo comando? è fattibile?.

E non è complicato se qualcuno te lo mostra, ma la prima volta ci è voluto un po' di tempo e discussioni per capirlo. In particolare voglio ringraziare e ringraziare il mio ex mentore Linux ed ex collega, Andrew Dalgleish: insieme abbiamo scoperto il modo migliore per farlo un po' meno di 10 anni.

Benvenuto in xargs con bash -c

Come abbiamo visto, anche quando i tubi vengono utilizzati in combinazione con xargs, saranno ancora presenti limitazioni per lo scripting di livello tecnico superiore. Prendiamo il nostro esempio sopra e iniettiamo le informazioni di debug senza post-elaborare il risultato. Regolarmente questo sarebbe difficile da raggiungere, ma non così con xargs combinato con bash -c:

dormire 300 &
pidof sonno | xargs -I{} eco "echo 'Il PID del tuo processo di sonno era: {}'; uccisione -9 {}; echo 'PID {} ora è stato chiuso'" | xargs -I{} bash -c "{}"

Una complessa sequenza di compilazione del comando xargs e l'uso di bash -c

Qui ne usiamo due xargs comandi. Il primo costruisce una riga di comando personalizzata, usando come input l'output del comando precedente nella pipe (essendo pidof sleep) e il secondo comando xargs esegue quel comando generato, personalizzato per input (importante!).

Perché personalizzare per voce? Il motivo è che xargs per impostazione predefinita elaborerà riga per riga attraverso il tuo input (l'output del comando precedente nella pipeline) ed eseguirà tutto ciò che è stato comandato di eseguire per ogni riga di input.

C'è molto potere qui. Ciò significa che puoi creare e creare qualsiasi comando personalizzato e quindi eseguirlo, totalmente privo di qualsiasi formato in cui si trovano i dati di input, e totalmente libero dal doversi preoccupare di come eseguirlo. L'unica sintassi che devi ricordare è questa:

qualche_comando | xargs -I{} eco "eco '...{}...'; più_comandi; più_comandi_con_o_senza{}" | xargs -I{} bash -c "{}"

Si noti che il nidificato echo (la seconda eco) davvero necessario solo se si desidera eseguire nuovamente il rendering del testo effettivo. Caso opposto, se il secondo echo non c'era, primo echo comincerebbe a mostrare "Il PID" …’ eccetera. e il bash -c la subshell non è stata in grado di analizzarlo come comando (IOW, "Il PID" …’ non è un comando e non può essere eseguito come tale, da qui l'eco secondario / nidificato).

Una volta che ti ricordi bash -c, il -I{} e il modo di echeggiare dall'interno di un'altra eco (e in alternativa, se necessario, potrebbero essere utilizzate sequenze di escape), ti ritroverai a usare questa sintassi più e più volte.

Diciamo che devi eseguire tre cose per file nella directory: 1) generare il contenuto del file, 2) spostalo in una sottodirectory, 3) eliminarlo. Regolarmente, ciò richiederebbe una serie di passaggi con diversi comandi a fasi, E se diventa più complesso, potresti anche aver bisogno di file temporanei. Ma è fatto molto facilmente usando bash -c e xargs:

eco '1' > a
echo '2' > b
echo '3' > c
mkdir subdir
ls --color=never | grep -v sottodirectory | xargs -I{} eco "gatto {}; mv {} sottodir; sottodirectory rm/{}" | xargs -I{} bash -c "{}"

Un mini script completamente funzionale basato su xargs e bash -c in un comando a riga singola

Primo, notando subito che è sempre una buona idea da usare --color=never di ls, per evitare problemi nel sistema utilizzando la codifica a colori per gli output dell'elenco delle directory (abilitato di default in Ubuntu), poiché questo spesso causa forti problemi di analisi perché i codici colore vengono effettivamente inviati al terminale e preceduti dalle voci dell'elenco della directory.

Per prima cosa creiamo tre file, un, essere, e una sottodirectory denominata subdir. Escludiamo questa sottodirectory dall'elenco delle directory con grep -v dopo che abbiamo notato che una rapida corsa di prova (senza eseguire i comandi, o in un altro modo, senza il secondo xargs), viene ancora visualizzata la sottodirectory.

È sempre essenziale testare prima i tuoi comandi complessi guardando l'output prima di passarli a un sottolivello bash con bash -c per la sua esecuzione.

Finalmente, usiamo esattamente lo stesso metodo visto in precedenza per costruire o ordinare; cat (mostrare) il file, sposta il file (indicato da {}) alla sottodirectory e, finire, elimina il file all'interno della sottodirectory. Vediamo che il contenuto di 3 record (1, 2, 3) viene visualizzato sullo schermo, e se controlliamo la directory corrente, i nostri file sono spariti. Possiamo anche vedere come non ci siano più file nella sottodirectory. Tutto ha funzionato bene.

Fine

Usando xargs essendo un grande potere per un utente Linux avanzato (e in questa circostanza) bash. Usando xargs in combinazione con bash -c porta ancora più potere; la capacità unica di creare righe di comando complesse e personalizzate 100% gratuito, senza bisogno di file o costruzioni intermedie, e senza bisogno di avere comandi impilati / in sequenza.

Godere!

Iscriviti alla nostra Newsletter

Non ti invieremo posta SPAM. Lo odiamo quanto te.