Esiste un comando Unix per anteporre alcuni dati di stringa a un file di testo?
Qualcosa di simile a:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
Esiste un comando Unix per anteporre alcuni dati di stringa a un file di testo?
Qualcosa di simile a:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
Risposte:
sed -i.old '1s;^;to be prepended;' inFile
-i
scrive la modifica in posizione ed esegue un backup se viene fornita un'estensione. (In questo caso, .old
)1s;^;to be prepended;
sostituisce l'inizio della prima riga con la stringa di sostituzione data, utilizzando ;
come delimitatore di comando.\n
dopo anteporre; a seconda delle loro esigenze. Ottima soluzione.
inFile
directory di inclusione nel suo percorso?
\n
. Avrei dovuto leggere prima i commenti. Dannazione.
'1s;^;my-prepended-line\;\n;'
printf '%s\n%s\n' "to be prepended" "$(cat text.txt)" >text.txt
git config --get-regex $arg | sed -r 's/\t{3}/\\n/g';
e questo incasina mentre converte i file \t
e \n
.
echo "to be prepended"$'\n'"$(cat text.txt)"
Sono sorpreso che nessuno ne abbia parlato.
cat <(echo "before") text.txt > newfile.txt
che è probabilmente più naturale della risposta accettata (stampare qualcosa e collegarlo a un comando di sostituzione è lessicograficamente controintuitivo).
... e dirottando ciò che ha detto ryan sopra, con sponge
non hai bisogno di un file temporaneo:
sudo apt-get install moreutils
<<(echo "to be prepended") < text.txt | sponge text.txt
EDIT: Sembra che questo non funzioni in Bourne Shell /bin/sh
Usando una stringa qui - <<<
, puoi fare:
<<< "to be prepended" < text.txt | sponge text.txt
<<(echo "to be prepended") < text.txt
e <<< "to be prepended" < text.txt
non funzionano in bash; richiedono zsh.
Questa è una possibilità:
(echo "to be prepended"; cat text.txt) > newfile.txt
probabilmente non potrai aggirare facilmente un file intermedio.
Alternative (può essere complicato con la fuga dalla shell):
sed -i '0,/^/s//to be prepended/' text.txt
cat <(echo "to be prepended") text.txt > newfile.txt
. A pensarci bene, non sono sicuro che il mio sia correlato, quindi sto postando una risposta separata.
Questo funzionerà per formare l'output. - indica lo standard input, che viene fornito tramite la pipe da echo.
echo -e "to be prepended \n another line" | cat - text.txt
Per riscrivere il file è necessario un file temporaneo in quanto non può essere reindirizzato nel file di input.
echo "to be prepended" | cat - text.txt > text.txt.tmp
mv text.txt.tmp text.txt
text.txt
come richiesto, ma lo visualizza su stdout. L'output potrebbe essere incanalato in un file diverso se funziona per l'OP
Preferisco la risposta di Adam
Possiamo rendere più facile l'uso della spugna . Ora non è necessario creare un file temporaneo e rinominarlo con
echo -e "to be prepended \n another line" | cat - text.txt | sponge text.txt
Nota:
Ciò potrebbe avere effetti collaterali inaspettati, in particolare la potenziale sostituzione di un collegamento simbolico con un file normale, la conclusione con autorizzazioni diverse sul file e la modifica della data di creazione (nascita) del file.
sed -i
, come nella risposta del principe John Wesley , cerca di ripristinare almeno i permessi originali, ma si applicano anche le altre limitazioni.
Ecco una semplice alternativa che utilizza un file temporaneo (evita di leggere l'intero file di input in memoria come fa la soluzione di shime ):
{ printf 'to be prepended'; cat text.txt; } > tmp.txt && mv tmp.txt text.txt
L'utilizzo di un comando group ( { ...; ...; }
) è leggermente più efficiente rispetto all'utilizzo di una subshell ( (...; ...)
), come nella soluzione di 0xC0000022L .
I vantaggi sono:
E 'facile da controllare se il nuovo testo dovrebbe essere direttamente preposta alla prima linea o se debba essere inserito come nuova linea (s) (semplicemente accodamento \n
al printf
argomento).
A differenza della sed
soluzione, funziona se il file di input è vuoto ( 0
byte).
La sed
soluzione può essere semplificata se l'intento è di anteporre una o più righe intere al contenuto esistente (supponendo che il file di input non sia vuoto):
sed
La i
funzione di inserisce intere righe:
Con GNU sed
:
# Prepends 'to be prepended' *followed by a newline*, i.e. inserts a new line.
# To prepend multiple lines, use '\n' as part of the text.
# -i.old creates a backup of the input file with extension '.old'
sed -i.old '1 i\to be prepended' inFile
Una variante portatile che funziona anche con macOS / BSD sed
:
# Prepends 'to be prepended' *followed by a newline*
# To prepend multiple lines, escape the ends of intermediate
# lines with '\'
sed -i.old -e '1 i\
to be prepended' inFile
Nota che la nuova riga letterale dopo \
è obbligatoria.
Utilizzando la venerabile ed
utility POSIX :
Nota:
ed
legge invariabilmente prima il file di input nel suo complesso in memoria.Per anteporre direttamente alla prima riga (come con sed
, questo non funzionerà se il file di input è completamente vuoto ( 0
byte)):
ed -s text.txt <<EOF
1 s/^/to be prepended/
w
EOF
-s
ed
messaggi di stato soppressi .ed
come here-document ( <<EOF\n...\nEOF
) su più righe , cioè tramite stdin ; per impostazione predefinita, l'espansione delle stringhe viene eseguita in tali documenti (le variabili di shell sono interpolate); cita il delimitatore di apertura per sopprimerlo (ad esempio <<'EOF'
).1
rende la prima riga la riga correntes
esegue una sostituzione di stringa basata su espressioni regolari sulla riga corrente, come in sed
; puoi includere caratteri di ritorno a capo letterali nel testo sostitutivo, ma devono essere \
preceduti da caratteri di escape.w
riscrive il risultato nel file di input (per il test, sostituire w
con ,p
per stampare solo il risultato, senza modificare il file di input).Per anteporre una o più righe intere :
Come con sed
, la i
funzione aggiunge invariabilmente una nuova riga finale al testo da inserire.
ed -s text.txt <<EOF
0 i
line 1
line 2
.
w
EOF
0 i
rende 0
(l'inizio del file) la riga corrente e avvia la modalità di inserimento ( i
); notare che i numeri di riga sono altrimenti 1
basati su..
su una riga separata.Probabilmente nulla di integrato, ma potresti scrivere il tuo abbastanza facilmente, in questo modo:
#!/bin/bash
echo -n "$1" > /tmp/tmpfile.$$
cat "$2" >> /tmp/tmpfile.$$
mv /tmp/tmpfile.$$ "$2"
Almeno qualcosa del genere ...
$$
Tuttavia, l' utilizzo non è sufficiente per il codice di produzione (attacco tramite collegamento simbolico di Google); ma è sicuramente meglio di un nome di file statico.
mktemp
In alcune circostanze il testo anteposto può essere disponibile solo da stdin. Allora questa combinazione funzionerà.
echo "to be prepended" | cat - text.txt | tee text.txt
Se vuoi omettere l' tee
output, aggiungi > /dev/null
.
tee
non cada text.txt
prima cat
di averlo letto? Penso di no, il che renderebbe questa soluzione pericolosa per la salute del file.
lenA=1000000; yes a | head -c $lenA > a.txt; lenB=10000; b=$(yes b | head -c $lenB); echo "$b" | cat - a.txt | tee a.txt > /dev/null
. Se lenA
è 1000000 (file da 1 lenB
MB ) ed è 10000 (anteprime di testo di 10 KB), il file "a.txt" viene sovrascritto con 20 KB di lettere "b". Questo è totalmente rotto. Ora, se usi 1Mb a.txt e 1Mb di testo per anteporre, tee
entra in un ciclo che genera file 7Gb +, ho dovuto interrompere il comando. Quindi, è ovvio che il risultato è imprevedibile per i grandi formati. Non ho informazioni se dovrebbe funzionare su piccole dimensioni.
Soluzione:
printf '%s\n%s' 'text to prepend' "$(cat file.txt)" > file.txt
Nota che questo è sicuro su tutti i tipi di input, perché non ci sono espansioni. Ad esempio, se vuoi anteporre !@#$%^&*()ugly text\n\t\n
, funzionerà semplicemente:
printf '%s\n%s' '!@#$%^&*()ugly text\n\t\n' "$(cat file.txt)" > file.txt
L'ultima parte da considerare è la rimozione degli spazi bianchi alla fine del file durante la sostituzione del comando "$(cat file.txt)"
. Tutte le soluzioni per questo sono relativamente complesse. Se desideri conservare le nuove righe alla fine di file.txt, consulta questo: https://stackoverflow.com/a/22607352/1091436
file.txt
è più grande di quello che può essere adattato nell'elenco degli argomenti a printf
.
Un altro modo di utilizzare sed
:
sed -i.old '1 {i to be prepended
}' inFile
Se la riga da anteporre è multilinea:
sed -i.old '1 {i\
to be prepended\
multiline
}' inFile
sed -i '1ito be prepended' inFile
- o è consentito solo per GNU sed?
sed
, il i
comando è seguito da una barra rovesciata e da una nuova riga, e ogni riga di input tranne l'ultima termina anche con una barra rovesciata. GNU sed
consente abbreviazioni sulla falsariga di cui chiedi, ma è solo GNU a sed
farlo. '
Come testato in Bash (in Ubuntu), se si inizia con un file di prova tramite;
echo "Original Line" > test_file.txt
puoi eseguire;
echo "$(echo "New Line"; cat test_file.txt)" > test_file.txt
oppure, se la versione di bash è troppo vecchia per $ (), puoi usare i backtick;
echo "`echo "New Line"; cat test_file.txt`" > test_file.txt
e ricevere il seguente contenuto di "test_file.txt";
New Line
Original Line
Nessun file intermedio, solo bash / echo.
Un'altra soluzione abbastanza semplice è:
$ echo -e "string\n" $(cat file)
cat
espansione dei parametri tra virgolette è una buona ragione per un voto negativo . Questo codice divide il contenuto del file in parole e passa ciascuna di quelle parole come argomento separato a echo
. Si perdono i confini dell'argomento originale, si perdono le nuove righe / tabulazioni / ecc. E le stringhe come \t
e \n
nel testo originale vengono sostituite con tabulazioni e nuove righe invece di essere mantenute com'erano.
Se ti piace vi / vim, questo potrebbe essere più il tuo stile.
printf '0i\n%s\n.\nwq\n' prepend-text | ed file
Consiglierei di definire una funzione e quindi di importarla e utilizzarla dove necessario.
prepend_to_file() {
file=$1
text=$2
if ! [[ -f $file ]] then
touch $file
fi
echo "$text" | cat - $file > $file.new
mv -f $file.new $file
}
Quindi usalo in questo modo:
prepend_to_file test.txt "This is first"
prepend_to_file test.txt "This is second"
Il contenuto del file sarà quindi:
This is second
This is first
Sto per utilizzare questo approccio per implementare un programma di aggiornamento del registro delle modifiche.