Frage

Das ist wahrscheinlich eine komplexe Lösung.

Ich suche einen einfachen Operator wie „>>“, aber zum Voranstellen.

Ich fürchte, es existiert nicht.Ich muss so etwas tun

 mv myfile tmp
 cat myheader tmp > myfile

Gibt es etwas Intelligenteres?

War es hilfreich?

Lösung

Die Hack Für eine rasche off-the-Manschette war Antwort, die viele upvotes gearbeitet und empfangen werden. Dann, als die Frage immer beliebter wurde und mehr Zeit verging, begann empört Leute berichten, dass es sorta gearbeitet, aber seltsame Dinge passieren könnte, oder es hat einfach nicht funktionieren, so wurde es heftig für eine Zeit Downvoted. Solcher Spaß.

Die Lösung nutzt die genaue Umsetzung von Datei-Deskriptoren auf Ihrem System und, weil Implementierung signifikant zwischen nixes variiert, ist es Erfolg völlig systemabhängig ist, definitiv nicht tragbar, und soll nicht auch nur vage wichtig für irgendetwas verlassen.

Nun, mit allem, was aus dem Weg die Antwort lautete:


Erstellen von weiterem Dateideskriptor für die Datei (exec 3<> yourfile) von dort zu, dass (>&3) Schreiben scheint die Lese- / Schreib auf gleiche Datei Dilemma zu überwinden. Funktioniert bei mir auf 600K Dateien mit awk. Doch den gleichen Trick versucht, scheitert ‚Katze‘ mit.

Vorbei an der prependage als Variable awk (-v TEXT="$text") überwindet die wörtliche Zitate Problem, das mit 'sed' tut diesen Trick verhindert.

#!/bin/bash
text="Hello world
What's up?"

exec 3<> yourfile && awk -v TEXT="$text" 'BEGIN {print TEXT}{print}' yourfile >&3

Andere Tipps

Dies nach wie vor verwendet eine temporäre Datei, aber zumindest ist es in einer Zeile:

echo "text" | cat - yourfile > /tmp/out && mv /tmp/out yourfile

Credit: BASH: voranstellen Ein Text / Linien, um eine Die Datei

echo '0a
your text here
.
w' | ed some_file

ed ist der Standard-Editor! http://www.gnu.org/fun/jokes/ed.msg.html

John Mee: Ihre Methode ist nicht garantiert, und wird wahrscheinlich fehlschlagen, wenn Sie mehr als 4096 Byte Sachen voranstellen (zumindest das ist, was mit Gnu awk passiert, aber ich nehme an anderen Implementierungen werden ähnliche Einschränkungen haben). Nicht nur wird es in diesem Fall nicht, aber es wird eine Endlosschleife ein, wo er seine eigene Ausgabe gelesen werden, wodurch die Datei wachsen, bis alle verfügbaren Raum gefüllt ist.

Versuchen Sie es selbst:

exec 3<>myfile && awk 'BEGIN{for(i=1;i<=1100;i++)print i}{print}' myfile >&3

(Warnung: tötet sie nach einer gewissen Zeit, oder es wird das Dateisystem füllen)

Darüber hinaus ist es sehr gefährlich, Dateien zu bearbeiten, die Art und Weise, und es ist sehr schlecht beraten, als wenn etwas passiert, während die Datei bearbeitet wird (Absturz, Festplatte voll) sind Sie fast garantiert mit der Datei in einem inkonsistenten gelassen werden Zustand.

Nicht möglich ohne eine temporäre Datei, aber hier geht eine oneliner

{ echo foo; cat oldfile; } > newfile && mv newfile oldfile

Sie können andere Tools wie ed oder Perl es ohne temporäre Dateien zu tun.

Es kann sich lohnen, unter Hinweis darauf, dass es oft eine mktemp , zumindest wenn das Skript immer mit root-Rechten ausgeführt werden. Sie könnten zum Beispiel die folgenden Schritte aus (wieder in bash):

(tmpfile=`mktemp` && { echo "prepended text" | cat - yourfile > $tmpfile && mv $tmpfile yourfile; } )

Wenn Sie diese auf Computern, die Sie steuern, installieren Sie das Paket „moreutils“ und verwenden „Schwamm“. Dann können Sie tun:

cat header myfile | sponge myfile

ein Bash heredoc Verwenden Sie die Notwendigkeit einer tmp-Datei vermeiden kann:

cat <<-EOF > myfile
  $(echo this is prepended)
  $(cat myfile)
EOF

Das funktioniert, weil $ (cat myfile) ausgewertet wird, wenn der Bash-Skript ausgewertet wird, bevor die Katze mit Umleitung ausgeführt wird.

unter der Annahme, dass die Datei, die Sie bearbeiten möchten, ist my.txt

$cat my.txt    
this is the regular file

Und die Datei, die Sie voranstellen wollen, ist Header

$ cat header
this is the header

Achten Sie darauf, eine letzte leere Zeile in der Header-Datei haben.
Jetzt können Sie prepend es mit

$cat header <(cat my.txt) > my.txt

Sie am Ende mit

$ cat my.txt
this is the header
this is the regular file

Soweit ich das funktioniert nur in ‚bash‘ kennen.

Wenn Sie beginnen, versuchen, die Dinge zu tun, die in der Schale-Skript schwierig geworden, würde ich stark in vorschlagen, Blick das Skript in einem „richtigen“ Skriptsprache Umschreiben (Python / Perl / Ruby-Datei / etc)

Wie für eine Zeile in eine Datei vorangestellt wird, ist es nicht möglich, dies über eine Rohrleitung zu tun, wie wenn Sie so etwas wie cat blah.txt | grep something > blah.txt tun, es versehentlich die Datei ausblendet. Es ist ein kleines Programm Befehl namens sponge Sie installieren können (Sie cat blah.txt | grep something | sponge blah.txt tun und es puffert die Inhalte der Datei, schreibt es dann in die Datei). Es ist ähnlich wie eine temporäre Datei aber Sie nicht, dass explizit zu tun haben. aber ich würde sagen, das ist eine „schlechte“ Anforderung als, sagen sie, Perl.

Es kann ein Weg sein, es über awk zu tun, oder ähnlich, aber wenn Sie verwenden Shell-Skript haben, denke ich, eine temporäre Datei ist bei weitem die einfachste (/ nur?) Art und Weise ..

EDIT: Dies ist gebrochen. Siehe , wenn in eine Datei mit Katze vorangestellt und tee

Die Abhilfemaßnahme zum Überschreiben Problem wird mit tee:

cat header main | tee main > /dev/null

Wie Daniel Velkov vermuten lässt, verwenden T-Stück.
Für mich ist so einfach intelligente Lösung:

{ echo foo; cat bar; } | tee bar > /dev/null

Die eine, die ich verwende. Dieser ermöglicht es Ihnen um, zusätzliche Zeichen, usw. in der Art und Weise Sie es angeben mögen:

echo -e "TEXTFIRSt\n$(< header)\n$(< my.txt)" > my.txt

P. S: nur es funktioniert nicht, wenn Dateien enthält Text mit Aufkantung, weil es als Escape-Zeichen interpretiert wird

Vor allem für Spaß / Shell-Golf, aber

ex -c '0r myheader|x' myfile

wird den Trick tun, und es gibt keine Rohrleitungen oder Umleitungen. Natürlich vi / ex ist nicht wirklich für nicht interaktive Verwendung, so vi kurz aufblitzen wird.

Warum nicht einfach den ed-Befehl (wie bereits von fluffle hier vorgeschlagen)?

ed liest die gesamte Datei in den Speicher und führt automatisch eine in-Place-Datei bearbeiten!

Also, wenn Sie Ihre Datei ist nicht so riesig ...

# cf. "Editing files with the ed text editor from scripts.",
# http://wiki.bash-hackers.org/doku.php?id=howto:edit-ed

prepend() {
   printf '%s\n' H 1i "${1}" . wq | ed -s "${2}"
}

echo 'Hello, world!' > myfile
prepend 'line to prepend' myfile

Und doch wäre eine andere Abhilfe offene Datei verwenden behandelt wie von Jürgen Hötzel in umleiten Ausgabe von sed 's / c / d /' myFile zu myFile

echo cat > manipulate.txt
exec 3<manipulate.txt
# Prevent open file from being truncated:
rm manipulate.txt
sed 's/cat/dog/' <&3 > manipulate.txt

Dies könnte alle in einer einzigen Zeile gestellt werden, natürlich.

Eine Variante cb0-Lösung für „keine temporäre Datei“ vorangestellt festen Text:

echo "text to prepend" | cat - file_to_be_modified | ( cat > file_to_be_modified ) 

Auch hier verlässt sich dies auf die Unterschale Ausführung - die (..) - die Katze zu vermeiden verweigern die gleiche Datei für Eingabe und Ausgabe haben

.

Hinweis: Zufrieden mit dieser Lösung. in meinem Mac Allerdings ist die Originaldatei verloren (dachte, es sollte nicht, aber es tut). Das könnte als durch Schreiben Sie Ihre Lösung festgelegt werden: echo "Text vorangestellt wird" | cat - file_to_be_modified | cat> tmp_file; mv tmp_file file_to_be_modified

Hier ist, was ich entdeckt:

echo -e "header \n$(cat file)" >file
sed -i -e '1rmyheader' -e '1{h;d}' -e '2{x;G}' myfile

. ACHTUNG: das muss ein bisschen mehr Arbeit des OP gerecht werden

Es sollte ein Weg sein, um den sed Ansatz @shixilun Arbeit trotz seiner Bedenken zu machen. Es muss ein bash Befehl seines Leerzeichen zu entkommen, wenn eine Datei in einen sed Ersatz-String lesen (zB Zeilenumbrüche mit ‚\ n‘ ersetzen. Shell-Befehlen vis und cat mit nicht druckbaren Zeichen umgehen kann, aber nicht Leerzeichen, so wird dies nicht lösen die OP das Problem:

sed -i -e "1s/^/$(cat file_with_header.txt)/" file_to_be_prepended.txt

versagt aufgrund der rohen Zeilenumbrüche in dem Ersatz Skript, das mit einem Linienfortsetzungszeichen () und vielleicht gefolgt von einer & vorangestellt werden muß, um die Schale zu halten und glücklich sed, wie this SO beantworten

sed hat eine Größenbeschränkung von 40K für nicht-globale Such ersetzen Befehle (kein Nachlauf / g nach dem Muster), so würde wahrscheinlich die beängstigende Pufferüberlauf Probleme von awk vermeiden, die anonym von gewarnt.

sed -i -e "1s/^/new first line\n/" old_file.txt

Mit $ (Befehl) können Sie die Ausgabe eines Befehls in eine Variable schreiben kann. Also habe ich es in drei Befehlen in einer Zeile und keine temporäre Datei.

originalContent=$(cat targetfile) && echo "text to prepend" > targetfile && echo "$originalContent" >> targetfile

Wenn Sie eine große Datei (einige hundert Kilobyte in meinem Fall) und den Zugang zu Python haben, ist dies viel schneller als cat Pipe-Lösungen:

python -c 'f = "filename"; t = open(f).read(); open(f, "w").write("text to prepend " + t)'

Eine Lösung mit printf:

new_line='the line you want to add'
target_file='/file you/want to/write to'

printf "%s\n$(cat ${target_file})" "${new_line}" > "${target_file}"

Sie können auch tun:

printf "${new_line}\n$(cat ${target_file})" > "${target_file}"

Aber in diesem Fall müssen Sie sicher sein, es gibt keine % überall, einschließlich des Inhalts der Zieldatei, so dass interpretiert werden kann und vermasseln Ihre Ergebnisse.

Sie können Perl-Befehlszeile:

perl -i -0777 -pe 's/^/my_header/' tmp

Wo -i wird eine Inline-Ersetzung der Datei erstellen und -0777 wird die gesamte Datei schlürfen und ^ Spiel macht nur der Anfang. -pe werden alle Zeilen drucken

Oder wenn my_header ist eine Datei:

perl -i -0777 -pe 's/^/`cat my_header`/e' tmp

Wenn die / e wird ein eval von Code in der Substitution ermöglichen.

current=`cat my_file` && echo 'my_string' > my_file && echo $current >> my_file

, wobei "my_file" ist die Datei voranstellen "my_string" zu.

Ich bin gefallen @ fluffle ed Ansatz die beste. Immerhin jedes Befehlszeile des Werkzeugschalters vs Skript-Editor-Befehle sind im Wesentlichen die gleiche Sache hier; wobei jede kleinere oder Dingsbums kein Skript-Editor Lösung „Sauberkeit“ zu sehen.

Hier ist mein Einzeiler angefügt .git/hooks/prepare-commit-msg eine in-repo .gitmessage Datei voranstellen Nachrichten zu begehen:

echo -e "1r $PWD/.gitmessage\n.\nw" | ed -s "$1"

Beispiel .gitmessage:

# Commit message formatting samples:
#       runlevels: boot +consolekit -zfs-fuse
#

Ich mache 1r statt 0r, denn das wird die leere ready-to-Schreibleitung auf die Datei aus der ursprünglichen Vorlage verlassen. Sie nicht eine leere Zeile auf Ihre .gitmessage setzen dann werden Sie sich mit zwei leeren Zeilen enden. -s unterdrückt diagnostische Informationen Ausgabe von ed.

Im Zusammenhang mit gehen durch diese, ich entdeckt , dass für vim-Buffs es ist auch gut zu haben:

[core]
        editor = vim -c ':normal gg'

Variablen, ftw?

NEWFILE=$(echo deb http://mirror.csesoc.unsw.edu.au/ubuntu/ $(lsb_release -cs) main universe restricted multiverse && cat /etc/apt/sources.list)
echo "$NEWFILE" | sudo tee /etc/apt/sources.list

Ich denke, dies ist die sauberste Variante ed ist:

cat myheader | { echo '0a'; cat ; echo -e ".\nw";} | ed myfile

als Funktion:

function prepend() { { echo '0a'; cat ; echo -e ".\nw";} | ed $1; }

cat myheader | prepend myfile

Wenn Sie in BASH sind Scripting, tatsächlich können Sie nur Ausgabe:

cat - yourfile  /tmp/out && mv /tmp/out yourfile

Das ist eigentlich im Complex Beispiel Sie sich in Ihrer eigenen Frage gestellt.

IMHO keine Shell-Lösung ist (und wird es nie sein), die konsequent und zuverlässig funktionieren würden, was auch immer die Größe der beiden Dateien myheader und myfile. Der Grund dafür ist, dass, wenn Sie, dass in eine temporäre Datei ohne wiederkehrende tun wollen (und ohne die Schale still in eine temporäre Datei, zum Beispiel durch Konstrukte wie exec 3<>myfile wieder auftreten zu lassen, Rohrleitungen tee, etc.

Die „echte“ Lösung, die Sie für Bedürfnisse suchen, um mit dem Dateisystem zur Geige, und es ist so nicht in User-Space zur Verfügung und wäre plattformabhängig: Sie fragen, das Dateisystem Zeiger in Verwendung durch myfile auf den aktuellen Wert zu ändern in dem Dateisystem, die von myheader EOF mit einem verketteten Link auf die aktuelle Dateisystem-Adresse der Dateisystem-Pointer für myheader und ersetzen durch myfile spitz. Dies ist nicht trivial und kann natürlich nicht von einem Nicht-Superuser erfolgen, und wahrscheinlich nicht vom Superuser entweder ... Spielen Sie mit Inodes, etc.

Sie können mehr oder weniger gefälschte diese Loop-Geräte verwenden, though. Siehe zum Beispiel diese SO fädelt .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top