Gibt es einen Unix-Befehl, um einer Textdatei einige Zeichenfolgendaten voranzustellen?
Etwas wie:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
Gibt es einen Unix-Befehl, um einer Textdatei einige Zeichenfolgendaten voranzustellen?
Etwas wie:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
Antworten:
sed -i.old '1s;^;to be prepended;' inFile
-ischreibt die Änderung an Ort und Stelle und erstellt ein Backup, wenn eine Erweiterung angegeben wird. (In diesem Fall .old)1s;^;to be prepended;Ersetzt den Anfang der ersten Zeile durch die angegebene Ersetzungszeichenfolge und verwendet sie ;als Befehlsbegrenzer.\nnach dem Voranstellen einfügen . je nach ihren Bedürfnissen. Ordentliche Lösung.
inFileInclude-Verzeichnisse in ihren Pfad aufgenommen werden?
\n. Hätte zuerst die Kommentare lesen sollen. Verdammt.
'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';und dies bringt es durcheinander, wenn es das \tund konvertiert \n.
echo "to be prepended"$'\n'"$(cat text.txt)"
Ich bin überrascht, dass niemand dies erwähnt hat.
cat <(echo "before") text.txt > newfile.txt
Das ist wohl natürlicher als die akzeptierte Antwort (etwas zu drucken und in einen Substitutionsbefehl zu leiten, ist lexikographisch kontraintuitiv).
... und entführen, was Ryan oben gesagt hat, spongeohne dass Sie eine temporäre Datei benötigen:
sudo apt-get install moreutils
<<(echo "to be prepended") < text.txt | sponge text.txt
EDIT: Sieht so aus, als würde dies in Bourne Shell nicht funktionieren /bin/sh
Mit einem Here-String - <<<können Sie Folgendes tun:
<<< "to be prepended" < text.txt | sponge text.txt
<<(echo "to be prepended") < text.txtund <<< "to be prepended" < text.txtKonstruktionen funktionieren nicht in Bash; sie benötigen zsh.
Dies ist eine Möglichkeit:
(echo "to be prepended"; cat text.txt) > newfile.txt
Sie werden wahrscheinlich nicht leicht um eine Zwischendatei herumkommen.
Alternativen (können umständlich sein, wenn die Schale entweicht):
sed -i '0,/^/s//to be prepended/' text.txt
cat <(echo "to be prepended") text.txt > newfile.txt . Wenn ich darüber nachdenke, bin ich mir nicht sicher, ob meine verwandt ist, also poste ich eine separate Antwort.
Dies wird funktionieren, um die Ausgabe zu bilden. Das - bedeutet Standardeingang, der über die Pipe vom Echo bereitgestellt wird.
echo -e "to be prepended \n another line" | cat - text.txt
Zum Umschreiben der Datei ist eine temporäre Datei erforderlich, die nicht in die Eingabedatei zurückgeleitet werden kann.
echo "to be prepended" | cat - text.txt > text.txt.tmp
mv text.txt.tmp text.txt
text.txtwie gewünscht vorangestellt, sondern auf stdout angezeigt. Die Ausgabe könnte in eine andere Datei geleitet werden, wenn dies für das OP funktioniert
Bevorzugen Sie Adams Antwort
Wir können die Verwendung von Schwamm vereinfachen . Jetzt müssen wir keine temporäre Datei erstellen und umbenennen durch
echo -e "to be prepended \n another line" | cat - text.txt | sponge text.txt
Hinweis:
Dies kann unerwartete Nebenwirkungen haben, insbesondere das Ersetzen eines Symlinks durch eine reguläre Datei, das Erhalten unterschiedlicher Berechtigungen für die Datei und das Ändern des Erstellungsdatums (des Geburtsdatums) der Datei.
sed -iWie in der Antwort von Prince John Wesley wird versucht, zumindest die ursprünglichen Berechtigungen wiederherzustellen, es gelten jedoch auch die anderen Einschränkungen.
Hier ist eine einfache Alternative, bei der eine temporäre Datei verwendet wird (es wird vermieden, dass die gesamte Eingabedatei wie bei der Shime-Lösung in den Speicher eingelesen wird):
{ printf 'to be prepended'; cat text.txt; } > tmp.txt && mv tmp.txt text.txt
Die Verwendung eines Gruppenbefehls ( { ...; ...; }) ist etwas effizienter als die Verwendung einer Unterschale ( (...; ...)), wie in der Lösung von 0xC0000022L .
Die Vorteile sind:
Es ist einfach zu steuern, ob der neue Text direkt der ersten Zeile vorangestellt oder als neue Zeile (n) eingefügt werden soll (einfach \nan das printfArgument anhängen ).
Im Gegensatz zur sedLösung funktioniert es, wenn die Eingabedatei leer ist ( 0Bytes).
Die sedLösung kann vereinfacht werden, wenn dem vorhandenen Inhalt eine oder mehrere ganze Zeilen vorangestellt werden sollen (vorausgesetzt, die Eingabedatei ist nicht leer):
sed's iFunktion fügt ganze Zeilen ein:
Mit 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
Eine tragbare Variante, die auch mit macOS / BSD funktioniert 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
Beachten Sie, dass der wörtliche Zeilenumbruch nach dem \erforderlich ist.
Verwenden des ehrwürdigen edPOSIX-Dienstprogramms :
Hinweis:
edLiest immer zuerst die gesamte Eingabedatei in den Speicher.So stellen Sie direkt in die erste Zeile voran (wie bei sedfunktioniert dies nicht, wenn die Eingabedatei vollständig leer ist ( 0Bytes)):
ed -s text.txt <<EOF
1 s/^/to be prepended/
w
EOF
-sedStatusmeldungen von unterdrückt .edals mehrzeiliges here-document ( <<EOF\n...\nEOF) bereitgestellt werden , dh über stdin ; Standardmäßig wird in solchen Dokumenten eine Zeichenfolgenerweiterung durchgeführt (Shell-Variablen werden interpoliert). zitieren Sie den Eröffnungsbegrenzer, um dies zu unterdrücken (z <<'EOF'. B. ).1 macht die 1. Zeile zur aktuellen Zeilesführt eine Regex-basierte Zeichenfolgenersetzung in der aktuellen Zeile durch, wie in sed; Sie können wörtliche Zeilenumbrüche in den Ersetzungstext aufnehmen, diese müssen jedoch \umgangen werden.wschreibt in die Eingabedatei das Ergebnis zurück (für die Prüfung, ersetzen wmit ,pnur drucken das Ergebnis, ohne die Eingabedatei zu verändern).So stellen Sie eine oder mehrere ganze Zeilen voran :
Wie bei fügt seddie iFunktion dem einzufügenden Text immer eine nachgestellte neue Zeile hinzu.
ed -s text.txt <<EOF
0 i
line 1
line 2
.
w
EOF
0 imacht 0(den Anfang der Datei) zur aktuellen Zeile und startet den Einfügemodus ( i); Beachten Sie, dass die Zeilennummern ansonsten 1basieren..einer eigenen Zeile abgeschlossen wird.Wahrscheinlich ist nichts eingebaut, aber Sie könnten ganz einfach Ihre eigenen schreiben:
#!/bin/bash
echo -n "$1" > /tmp/tmpfile.$$
cat "$2" >> /tmp/tmpfile.$$
mv /tmp/tmpfile.$$ "$2"
Zumindest so etwas ...
$$ist jedoch für Produktionscode nicht ausreichend (Google Symlink-Angriff). aber es ist sicherlich besser als ein statischer Dateiname.
mktemp
Unter bestimmten Umständen ist vorangestellter Text möglicherweise nur bei stdin verfügbar. Dann soll diese Kombination funktionieren.
echo "to be prepended" | cat - text.txt | tee text.txt
Wenn Sie die teeAusgabe weglassen möchten , fügen Sie sie hinzu > /dev/null.
teedie nicht verstopft, text.txtbevor catman sie lesen kann? Ich denke nicht - was diese Lösung für die Gesundheit der Datei gefährlich machen würde.
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. Wenn lenA1000000 (1 MB Datei) und lenB10000 (10 KB Text vorangestellt) ist, wird die Datei "a.txt" mit 20 KB "b" Buchstaben überschrieben. Das ist total kaputt. Wenn Sie jetzt 1 MB a.txt und 1 MB Text zum Voranstellen verwenden und teein eine Schleife gehen , die eine 7 GB + -Datei generiert, musste ich den Befehl stoppen. Es ist also offensichtlich, dass das Ergebnis für große Größen nicht vorhersehbar ist. Ich habe keine Informationen, ob es bei kleinen Größen funktionieren soll.
Lösung:
printf '%s\n%s' 'text to prepend' "$(cat file.txt)" > file.txt
Beachten Sie, dass dies für alle Arten von Eingaben sicher ist, da keine Erweiterungen vorhanden sind. Wenn Sie beispielsweise voranstellen möchten, !@#$%^&*()ugly text\n\t\nfunktioniert dies nur:
printf '%s\n%s' '!@#$%^&*()ugly text\n\t\n' "$(cat file.txt)" > file.txt
Der letzte Teil, der berücksichtigt werden muss, ist das Entfernen von Leerzeichen am Ende der Datei während der Befehlsersetzung "$(cat file.txt)". Alle Workarounds hierfür sind relativ komplex. Wenn Sie Zeilenumbrüche am Ende von file.txt beibehalten möchten, lesen Sie Folgendes: https://stackoverflow.com/a/22607352/1091436
file.txtgrößer ist, als in die Argumentliste aufgenommen werden kann printf.
Ein anderer Weg mit sed:
sed -i.old '1 {i to be prepended
}' inFile
Wenn die vorangestellte Zeile mehrzeilig ist:
sed -i.old '1 {i\
to be prepended\
multiline
}' inFile
sed -i '1ito be prepended' inFile- oder ist es nur für GNU sed erlaubt?
sedden iBefehl ein Backslash und eine Newline, und jede Eingabezeile mit Ausnahme der letzten endet ebenfalls mit einem Backslash. GNU sederlaubt Abkürzungen in der Richtung, nach der Sie fragen, aber nur GNU sedtut dies. '
Wie in Bash (in Ubuntu) getestet, wenn mit einer Testdatei über begonnen wird;
echo "Original Line" > test_file.txt
Sie können ausführen;
echo "$(echo "New Line"; cat test_file.txt)" > test_file.txt
oder wenn die Version von bash für $ () zu alt ist, können Sie Backticks verwenden;
echo "`echo "New Line"; cat test_file.txt`" > test_file.txt
und den folgenden Inhalt von "test_file.txt" erhalten;
New Line
Original Line
Keine Zwischendatei, nur Bash / Echo.
Eine andere ziemlich einfache Lösung ist:
$ echo -e "string\n" $(cat file)
catParametererweiterung nicht in doppelte Anführungszeichen zu setzen, ist ein ziemlich guter Grund für eine Abwertung . Dieser Code teilt den Inhalt der Datei in Wörter auf und übergibt jedes dieser Wörter als separates Argument an echo. Sie verlieren die ursprünglichen Argumentgrenzen, Sie verlieren Zeilenumbrüche / Tabulatoren / etc. Und Zeichenfolgen wie \tund \nim Originaltext werden durch Tabulatoren und Zeilenumbrüche ersetzt, anstatt so zu bleiben, wie sie waren.
Wenn Sie vi / vim mögen, ist dies möglicherweise eher Ihr Stil.
printf '0i\n%s\n.\nwq\n' prepend-text | ed file
Ich würde empfehlen, eine Funktion zu definieren und diese dann zu importieren und bei Bedarf zu verwenden.
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
}
Dann benutze es so:
prepend_to_file test.txt "This is first"
prepend_to_file test.txt "This is second"
Ihr Dateiinhalt lautet dann:
This is second
This is first
Ich werde diesen Ansatz für die Implementierung eines Änderungsprotokoll-Updaters verwenden.