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
-iscrive 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.\ndopo anteporre; a seconda delle loro esigenze. Ottima soluzione.
inFiledirectory 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 \te \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 spongenon 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.txte <<< "to be prepended" < text.txtnon 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.txtcome 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 \nal printfargomento).
A differenza della sedsoluzione, funziona se il file di input è vuoto ( 0byte).
La sedsoluzione 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):
sedLa ifunzione 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 edutility POSIX :
Nota:
edlegge 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 ( 0byte)):
ed -s text.txt <<EOF
1 s/^/to be prepended/
w
EOF
-sedmessaggi di stato soppressi .edcome 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 correntesesegue 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.wriscrive il risultato nel file di input (per il test, sostituire wcon ,pper stampare solo il risultato, senza modificare il file di input).Per anteporre una o più righe intere :
Come con sed, la ifunzione aggiunge invariabilmente una nuova riga finale al testo da inserire.
ed -s text.txt <<EOF
0 i
line 1
line 2
.
w
EOF
0 irende 0(l'inizio del file) la riga corrente e avvia la modalità di inserimento ( i); notare che i numeri di riga sono altrimenti 1basati 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' teeoutput, aggiungi > /dev/null.
teenon cada text.txtprima catdi 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 lenBMB ) 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, teeentra 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 icomando è 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 sedconsente abbreviazioni sulla falsariga di cui chiedi, ma è solo GNU a sedfarlo. '
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)
catespansione 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 \te \nnel 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.