Comando gatto ed eco


14

Vorrei concatenare l'output di echo con il contenuto di un file. Ho provato il seguente comando:

echo "abc" | cat 1.txt > 2.txt

ma il 2.txtfile contiene solo il contenuto di 1.txt. Perché non funziona?


3
Programmi come catleggere solo dallo standard input se non hanno argomenti sul nome file.
Barmar,

Risposte:


23

Non funziona perché il catprogramma nella sequenza di pipe non è stato istruito a leggere l' echooutput del programma dall'input standard.

È possibile utilizzare -come nome di file pseudo per indicare l'input standard a cat. Da man catsu un'installazione msys2:

EXAMPLES
       cat f - g
              Output f's contents, then standard input, then g's contents.

Allora prova

echo "abc" | cat - 1.txt > 2.txt

anziché.


21

Come notato da altri, il comando originale non riesce perché cat 1.txtignora il suo input standard. Indica che dovrebbe essere il suo primo argomento ( cat - 1.txt) o usa il reindirizzamento dei blocchi per reindirizzare echo abc e cat 1.txt insieme. Per dire:

{ echo abc; cat 1.txt; } > 2.txt 

Estratto pertinente del manuale ( man bash):

Comandi
composti Un comando composto è uno dei seguenti. Nella maggior parte dei casi, un elenco nella descrizione di un comando può essere separato dal resto del comando da una o più nuove righe e può essere seguito da una nuova riga al posto di un punto e virgola.

(elenco)

    l'elenco viene eseguito in un ambiente subshell (vedere AMBIENTE DI ESECUZIONE DEI COMANDI di seguito). Le assegnazioni di variabili e i comandi integrati che influiscono sull'ambiente della shell non rimangono attivi dopo il completamento del comando. Lo stato di ritorno è lo stato di uscita dell'elenco.

{elenco; }

    l'elenco viene semplicemente eseguito nell'attuale ambiente shell.  l'elenco deve essere terminato con una nuova riga o punto e virgola. Questo è noto come comando di gruppo . Lo stato di ritorno è lo stato di uscita dell'elenco . Si noti che a differenza dei metacaratteri (e ), {e }sono parole riservate e devono comparire laddove una parola riservata può essere riconosciuta. Dal momento che non causano un'interruzione di parola, devono essere separati dall'elenco da spazi bianchi o da un altro metacarattere della shell.

La prima opzione (ambiente subshell) ha un sacco di effetti collaterali, molti dei quali se non tutti sono irrilevanti per il tuo scenario; tuttavia, se è sufficiente reindirizzare l'output di un gruppo di comandi, è preferibile l'opzione n. 2 qui (comando di gruppo).


7
( echo "abc"; cat 1.txt ) > 2.txt

Hai inviato l'output dell'eco a cat, ma cat non è stato utile per l'input e l'hai ignorato. Ora i comandi vengono eseguiti uno dopo l'altro e il loro output viene raggruppato (tra parentesi) e diretto in 2.txt.


1
Questa risposta può essere migliorata spiegando come funziona e perché il tentativo originale del PO non funziona.
Bob

OK, ho provato.
Gerard H. Pille,

5
Qui non è richiesta espressamente una subshell, forse sarebbe meglio usare un comando di gruppo. Vedi la mia risposta per maggiori dettagli.
Nubarke,

Ah, ma non userei mai bash.
Gerard H. Pille,

1
@ GerardH.Pille: mentre la risposta di Daniel cita bash(1), descrive il comportamento che ogni shell conforme a POSIX deve supportare.
G-Man dice 'Reinstate Monica' il

2

Il tuo comando cat 1.txtnon fa nulla con l'output di echo "abc".

Invece: (echo "abc"; cat 1.txt) > 2.txt scriverà l'output di entrambi i comandi in 2.txt.


Questa risposta può essere migliorata spiegando come funziona l'alternativa suggerita.
Bob

1

In qualsiasi shell POSIX è possibile utilizzare la sostituzione dei comandi da utilizzare cat filecome input per echo:

echo $(cat file1.txt) "This Too"

In Bash puoi usare la sostituzione di processo e usare echo come un altro "file" per cat, come in:

cat file1.txt <(echo This Too)

quindi reindirizza o reindirizza l'output come ritieni opportuno.

Come ogni altra risposta dice, il gatto ignora lo stdin se ha un file da guardare. (Mi piacciono anche le risposte di Daniel e mvw, +1 per loro)


1
Questa risposta può essere migliorata spiegando perché il tentativo originale del PO non funziona (e quindi perché questo è invece necessario).
Bob,

1
La <(command)costruzione è un'estensione bash. Non è POSIX, quindi non puoi fare affidamento su di esso negli script che dovrebbero essere eseguiti con /bin/sh.
Rhialto supporta Monica il

0

Solo un'ipotesi, ma sembra che tu abbia un processo ripetibile, che è un buon candidato per un alias o una funzione. Gli alias sono di solito scorciatoie per invocare comandi bash, come abbreviazioni, su un singolo flusso di input come argomento / i.

alias hg="history | grep"

Tuttavia, in questo caso, una funzione sarebbe più leggibile, poiché si stanno combinando più flussi di input discreti (2) e più comandi bash. Hai due argomenti, il primo è una stringa e l'altro un percorso file. Alla fine, si desidera che il risultato venga scritto nel flusso di output stdout.

Da un prompt della CLI, digitare questo:

# ecat()        
{
echo ${1}
cat ${2}
}

La tua funzione si chiama ecat, che è memorabile.

Ora puoi invocare come

ecat "abc" 1.txt

Per aggiungere, è sufficiente fornire una destinazione di output diversa a stdout:

ecat "abc" 1.txt >> 2.txt

L'operatore di reindirizzamento append '>>' aggiungerà l'output alla fine del file specificato.

Se ti piace, aggiungi al tuo file ~ / .bashrc per il riutilizzo.

declare -f ecat >> ~/.bashrc

Ciò significa anche che puoi decorare, ecc., All'interno della definizione della tua funzione.

Anche una buona idea per proteggere i file dalla sovrascrittura aggiungendo questo al tuo ~ / .bashrc

set noclobber

2
Affinché la tua funzione si comporti correttamente, devi usare "$1"e "$2". In questo contesto, le parentesi graffe non fanno nulla di buono. Vedere ${name}non significa quello che pensi lo fa ... .
G-Man dice "Ripristina Monica" il

1
In che modo il noclobbersuggerimento risponde alla domanda attuale? (Sono anche molto poco convinto che sia un buon consiglio - la modifica del comportamento globale tende a rompere gli script / i consigli / le pratiche costruiti tenendo conto delle impostazioni predefinite).
Charles Duffy,

0

Il seguente codice funzionerà anche:

echo abc >> 1.txt && cat 1.txt > 2.txt

L'output di echo abc verrà aggiunto a 1.txt con >> Dopodiché && gli dirà di eseguire il prossimo set di comandi che eseguirà la catenatura di 1.txt e quindi l'output su 2.txt . Fondamentalmente, aggiunge l'output del primo comando in 1.txt e quindi invia l'output di 1.txt in 2.txt.

Se vuoi che l'abc appaia per primo, puoi usare il seguente codice:

echo abc >> 2.txt && cat 1.txt >> 2.txt

1
Questa volontà (1) mettere abcin fondo di 2.txt; la domanda lo vuole in alto. (2)  modifica il 1.txtfile; questo è inaccettabile.
G-Man dice 'Reinstate Monica' il

Dove lo dice? Ringger81 non ha mai specificato dove in 2.txt voleva che apparisse. Stai assumendo cose che la domanda non afferma mai.
Nasir Riley

(1) OK, sollevi un punto valido su # 1. Mentre la domanda menziona "output da echo" prima di "contenuto di un file" nel testo, e quindi inserisce il comando echobefore catnel comando di esempio, suppongo che non dice mai esattamente, esplicitamente , che vuole l'output di echo prima del contenuto del file di input. Sembra proprio che la maggior parte delle persone lo interpretasse in quel modo. (2)  1.txtè un file di input. La domanda non dice nulla sulla modifica 1.txt. Il fatto che i file di input non debbano essere modificati è ovvio.
G-Man dice "Ripristina Monica" il

Posso capire il tuo punto di non modificare il file imput. Il mio secondo codice otterrà l'effetto desiderato senza farlo.
Nasir Riley

1
Aprire un file, accodarlo, chiuderlo , riaprirlo, accodarlo di nuovo ... perché farlo piuttosto che aprirlo una volta sola e mantenere il reindirizzamento in atto per entrambe le operazioni?
Charles Duffy,
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.