Come faccio ad aggiungere testo all'inizio di un file in Bash?


285

Ciao, voglio anteporre il testo a un file. Ad esempio, voglio aggiungere attività all'inizio di un file todo.txt. Sono a conoscenza, echo 'task goes here' >> todo.txtma ciò aggiunge la riga alla fine del file (non quello che voglio).


2
Se non c'è un modo efficace per farlo per file di grandi dimensioni: unix.stackexchange.com/questions/87772/…
Ciro Santilli 22 改造 中心 法轮功 六四 事件

@veresti dare un'occhiata a questo metodo superuser.com/a/1352628/11116
Evan Carroll

Risposte:


374
echo 'task goes here' | cat - todo.txt > temp && mv temp todo.txt

o

sed -i '1s/^/task goes here\n/' todo.txt

o

sed -i '1itask goes here' todo.txt

4
il primo funziona alla grande! ti dispiacerebbe spiegare la logica? non sono particolarmente sicuro di come interpretare la sintassi.
user479534,

44
@ user8347: Pipe ( |) il messaggio ( echo '...') a catcui utilizza -(input standard) come primo file e todo.txtcome secondo. catCONCATENA più file. Invia l'output ( >) a un file denominato temp. Se non ci sono errori ( &&) da catallora rinomina ( mv) il tempfile torna al file originale ( todo.txt).
Dennis Williamson,

1
@itaifrenkel: dovrei vedere quello che hai fatto, ma se catriceve una barra rovesciata letterale n, non lo convertirà in una nuova riga. Qualcos'altro deve averlo fatto. Invece di cat, prova a hexdump -Ceseguire il piping in per vedere se stai effettivamente inviando backslash e n o se si tratta di una nuova riga. Puoi anche provare cat -ea mostrare le terminazioni di riga.
Dennis Williamson,

1
L'uso di 2 e 3 (3 mi sembra più semplice) ti consente di anteporre il testo a più file contemporaneamente.
Felix,

4
@Kira: i 1mezzi eseguono il comando successivo solo sulla riga uno del file e il icomando è insert. Cerca nella pagina man sotto la sezione "Indirizzi" e nella sezione "Comandi a indirizzo zero o uno".
Dennis Williamson,

73

Un'opzione più semplice secondo me è:

echo -e "task goes here\n$(cat todo.txt)" > todo.txt

Questo funziona perché il comando all'interno di $(...)viene eseguito prima che todo.txtvenga sovrascritto> todo.txt

Mentre le altre risposte funzionano bene, lo trovo molto più facile da ricordare perché uso ogni giorno echo e cat.

EDIT: Questa soluzione è una pessima idea se ci sono delle barre rovesciate todo.txt, perché grazie -eall'eco della bandiera le interpreterà. Un altro modo molto più semplice per inserire nuove righe nella stringa della prefazione è ...

echo "task goes here
$(cat todo.txt)" > todo.txt

... semplicemente per usare le nuove linee. Certo, non è più un one-liner, ma realisticamente non era nemmeno un one-liner prima. Se lo stai facendo all'interno di uno script e sei preoccupato per il rientro (ad es. Lo stai eseguendo all'interno di una funzione), ci sono alcune soluzioni alternative per adattarlo perfettamente, incluso ma non limitato a:

(echo 'task goes here' && cat todo.txt) > todo.txt
echo 'task goes here'$'\n'"$(cat todo.txt)" > todo.txt

Inoltre, se ti interessa se una nuova riga viene aggiunta alla fine di todo.txt, non usarle. Bene, tranne il penultimo. Questo non scherza con la fine.


1
Non riesco affatto a eseguire $ (...).
SCL

2
Potrebbe funzionare meglio (o affatto) con virgolette doppie anziché singole ...
inkaphink

5
Le -esequenze di escape convertite anche all'interno di todo.txt non saranno convertite?
mk12

2
Resa delle soluzioni alternative -> cat: <nome file destinazione>: il file di input è il file di output ...
ingyhere

printf sarebbe molto più coerente su tutte le piattaforme e generalmente dovrebbe funzionare in modo più fluido rispetto a echo -e
Peter Berg,

28

L' moreutilsavere un bel strumento chiamato sponge:

echo "task goes here" | cat - todo.txt | sponge todo.txt

"Assorbirà" STDIN e quindi scriverà nel file, il che significa che non devi preoccuparti dei file temporanei e spostarli.

Puoi ottenere moreutilscon molte distro Linux, attraverso apt-get install moreutilso su OS X usando Homebrew , con brew install moreutils.


Vorrei andare per (echo 'ble'; cat todo.txt):-)
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

11

Puoi usare Vim in modalità Ex:

ex -s -c '1i|task goes here' -c x todo.txt
  1. 1 seleziona la prima riga

  2. i inserire

  3. x salva e chiudi


5

È possibile creare un nuovo file temporaneo.

echo "new task" > new_todo.txt
cat todo.txt >> new_todo.txt
rm todo.txt
mv new_todo.txt todo.txt

Puoi anche usare sedo awk. Ma sostanzialmente succede la stessa cosa.


1
Supponi di essere a corto di spazio su disco in modo che new_todo.txtvenga scritto solo parzialmente. La soluzione sembra perdere il file originale.
NPE,

Chi esaurisce lo spazio su disco? ;-) È solo un semplice esempio.
Keith,

2
@Keith Qualcuno che lavora su una VM che non si aspettava di aver bisogno di un'unità virtuale particolarmente grande. O qualcuno sta spostando un file di grandi dimensioni. In ogni caso, il vero argomento contro questo è permessi di directory; se non si dispone dell'autorizzazione per creare nuovi file nella directory specificata, l'unico comando che verrà eseguito correttamente nello script è il rmfile originale.
Parthian Shot

3

Se il file di testo è abbastanza piccolo da adattarsi alla memoria, non è necessario creare un file temporaneo per sostituirlo. Puoi caricare tutto in memoria e riscriverlo nel file.

echo "$(echo 'task goes here' | cat - todo.txt)" > todo.txt

È impossibile aggiungere righe all'inizio del file senza sovrascrivere l'intero file.


Solo per porre la domanda ovvia: dov'è il limite di caratteri delle variabili shell?
nixda,

Per quanto ne so, è limitato solo dalla quantità di memoria disponibile. Ho riempito le variabili ben oltre 100 MB in memoria. text=$(cat file). Fai
Rucent88

2

Non è possibile inserire contenuto all'inizio di un file. L'unica cosa che puoi fare è sostituire il contenuto esistente o aggiungere byte dopo l'attuale fine del file.

Qualsiasi soluzione alla tua domanda richiede quindi la creazione di un file temporaneo (o buffer) (in memoria o su disco) che alla fine sovrascriverà il file originale.

Fai attenzione a non perdere i dati preservando il file originale durante la creazione di quello nuovo, nel caso in cui il file system sia pieno durante il processo. per esempio:

cat <(echo task go there) todo.txt > todo.txt.new && mv todo.txt.new todo.txt

I downvoter sono invitati a spiegare la loro motivazione. Nessuna delle restanti risposte, compresa quella accettata, non contraddice nulla nella mia risposta.
jlliagre,

Questo è difficile da analizzare poiché le <...> sembrano parentesi, che presumo non lo siano. Uno spazio tra <e il (potrebbe aiutare?
silente

Questo non funziona per me. echo HOME=\"/g/Users/timregan/\" | cat - 'F:\Program Files\Git\etc\profile'funziona ma cat <echo HOME=\"/g/Users/timregan/\" 'F:\Program Files\Git\etc\profile'dà l'errore "echo: nessun file o directory"
silente

@dumbledad Stai pensando troppo alla mia risposta. Non c'è niente per te da analizzare. Uno spazio tra il <e il (spezzerebbe la sintassi. Provacat <(echo HOME=\"/g/Users/timregan/\") 'F:\Program Files\Git\etc\profile'
jlliagre,


0

GitBash + Windows10 + Multline :

Ecco una versione che ti consente di utilizzare stringhe multilinea .

##############################################
## This section for demo purpose only,      ##
## So you can save entire file as           ##
## whatever.sh and run it.                  ##
##                                          ##
##############################################
> MY_TARGET_FILE.txt ##Make Or Clear File
echo "[STARTER_CONTENT]" >> MY_TARGET_FILE.txt
##############################################

## Below is main code:

##################################################
TARGET_FILE_VARIABLE="MY_TARGET_FILE.txt"
ADD_TO_HEAD_VARIABLE=$(cat << "HEREDOC_HEAD_TEXT"
//|  +-------------------------------------+   |//
//|  |                                     |   |//
//|  |     MESSAGE_FOR_HEAD_OF_FILE        |   |//
//|  |                                     |   |//
//|  +-------------------------------------+   |//
HEREDOC_HEAD_TEXT
)
##################################################
TAR=$TARGET_FILE_VARIABLE                       ##
TEX=$ADD_TO_HEAD_VARIABLE                       ##
echo "$TEX" | cat - $TAR > TEMP && mv TEMP $TAR ##
##################################################

## Expected contents of MY_TARGET_FILE.txt :
## //|  +-------------------------------------+   |//
## //|  |                                     |   |//
## //|  |     MESSAGE_FOR_HEAD_OF_FILE        |   |//
## //|  |                                     |   |//
## //|  +-------------------------------------+   |//
## [STARTER_CONTENT]
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.