Was ist der einfachste Weg, um am Anfang jeder Zeile der Datei über die Befehlszeile eine Zeichenfolge hinzuzufügen?

8

Ich suche nach einer Möglichkeit, am Anfang jeder Zeile eine Zeichenfolge einzufügen (dieselbe Zeichenfolge für jede Zeile). Nicht anpassbar, sondern leicht zu merken und auf jeder POSIX-kompatiblen Plattform (und auch auf jeder Shell) verfügbar.

Syntagma
quelle

Antworten:

8

Sie können verwenden sed:

sed -i 's/^/your_string /' your_file

Beachten Sie, dass die -iOption dank der Kommentare von Stephane und Marco nicht POSIX ist. Ein POSIX-Weg, um das oben genannte zu tun, wäre

sed 's/^/your_string /' your_file > tmp_copy && mv tmp_copy your_file

oder perl:

perl -pi -e 's/^/your_string /' your_file

Erläuterung

Beide Befehle führen eine Regex-Ersetzung durch und ersetzen den Anfang einer Zeile ( ^) durch die gewünschte Zeichenfolge. Der -iSchalter in beiden Befehlen stellt sicher, dass die Datei an Ort und Stelle bearbeitet wird (dh die Änderungen werden in der Datei wiedergegeben, anstatt in stdout gedruckt zu werden).

sedsollte auf jedem POSIX-kompatiblen Betriebssystem perlverfügbar sein und sollte auf den meisten modernen Unices verfügbar sein, außer vielleicht auf denen, die sich die Mühe gemacht haben , es zu entfernen.

Joseph R.
quelle
1
Kleine Korrektur: Der -iSwitch bearbeitet die Datei nicht an Ort und Stelle. Es erstellt eine neue Datei und überschreibt die ursprüngliche, nachdem sie fertig ist (Beweis: Der Inode ändert sich). Es gibt nicht viele Tools, die tatsächlich direkt bearbeitet werden, was eine gefährliche Operation ist. Da Sie POSIX erwähnen, ist der -iSwitch für eine POSIX-kompatible Version nicht obligatorisch sed, sondern eine Funktion einiger bestimmter Implementierungen.
Marco
2
sed -iist nicht POSIX. Es ist GNU. FreeBSD sedhat eine ähnliche Option, aber Sie brauchen sed -i ''dort.
Stéphane Chazelas
@Marco Ich bin mir bewusst , dass -ieine temporäre Kopie erstellt (das ist , warum ich sagte , werden die Änderungen reflektiert in der Originaldatei); Ich meinte, dass Sie die gleiche Semantik wie bei der In-Place-Substitution erhalten. Bitte überprüfen Sie, ob die aktualisierte Antwort POSIX-kompatibel ist.
Joseph R.
Genau genommen werden die Änderungen in einer neuen Datei mit demselben Namen wie das Original wiedergegeben.
Keith Thompson
1
Ich verwende häufig $$(die Prozess-ID der aktuellen Shell) als Teil eines temporären Dateinamens. Es vermeidet die Mühe, jedes Mal an einen garantierten eindeutigen Namen zu denken:command filename > filename.$$ && mv filename.$$ filename
Keith Thompson
14
:|paste -d'foo ' - - - - input > output

(nur ein Scherz, obwohl Sie wahrscheinlich feststellen werden, dass es die schnellste aller hier veröffentlichten Lösungen ist: -b).

Der kanonische Weg ist:

sed 's/^/foo /' < input > output

Es ist jedoch nicht einfach an beliebige Zeichenfolgen anzupassen. Zum Beispiel,

sed "s/^/$var /"

Dies funktioniert nur , wenn $varnicht enthält, &, \, /noch Zeilenumbrüche.

In jener Hinsicht,

export var
awk '{print ENVIRON["var"], $0}'

oder

perl -pe '$_="$ENV{var} $_"'

würde besser funktionieren.

Stéphane Chazelas
quelle
das ist etwas interessantes ...: P
Rahul Patil
4

Ich präsentiere eine Lösung, indem awkich den String "foo" voranstelle.

awk '{ print "foo", $0; }' input > output

awkist plattformübergreifend und auf jedem POSIX-System verfügbar. Es wird keine direkte Bearbeitung durchgeführt. Wenn Sie eine Datei bearbeiten möchten, ohne eine zweite zu erstellen, müssen Sie eine temporäre Datei verwenden. Siehe Josephs sedAntwort, sie zeigt die Syntax. Ein weiterer Hack besteht darin, die folgende Syntax zu verwenden, mit der im Grunde genommen eine temporäre Datei mit demselben Dateinamen wie die Originaldatei erstellt wird.

{ rm file; awk '{ print "foo", $0 }' > file; } < file
Marco
quelle
reducto# wc -l foo`914 foo` reducto# { rm foo ; awk '{ print "prepend" , $0 }' > foo } < foo >Das scheint nicht zu funktionieren. Ich habe es versucht, weil mich die Umleitung zum Original nervös gemacht hat, aber es wird nicht einmal anfangen.
Kurtm
1
Dieses Beispiel funktioniert, wenn Klammern für die Außenseite anstelle von geschweiften Klammern verwendet werden.
Kurtm
4

Sie können die Probleme der direkten Bearbeitung mit den Stream-Tools vermeiden, indem Sie ein Tool verwenden, das normalerweise die direkte Bearbeitung durchführt - einen Editor!

ex sample.txt -c "%s/^/foo /" -c wq

Es gibt einen zusätzlichen Vorteil, dass die Befehle für jeden, der sich mit dem einen wahren Editor auskennt, einfach und offensichtlich sind.

Mike DeAngelo
quelle
2

Sie können dies verwenden perl, um dies zu tun:

$ perl -pi -e 's/^/mystring /' afile.txt

Beispiel

Erstellen Sie eine Beispieldatei.

$ seq 5 > afile.txt

$ cat afile.txt
1
2
3
4
5

Führen Sie den obigen Befehl aus:

$ perl -pi -e 's/^/mystring /' afile.txt

$ cat afile.txt
mystring 1
mystring 2
mystring 3
mystring 4
mystring 5
slm
quelle
Perl scheint heutzutage universell zu sein, war es aber lange nicht. Und ich wette, es gibt ein paar seltene UNIX-Varianten, die sich standhaft weigern, Perl als Teil der Basis zu haben. Etwas zu beachten.
Kurtm
@kurtm siehe die Diskussion hier . Anscheinend hat AIX standardmäßig weder Perl noch eingebettete Systeme.
Terdon
2
@ DavidSainty - es ist universell genug. Das Q wurde mit Bash getaggt, daher fällt es mir sehr schwer, mir ein System vorzustellen, das Bash, aber nicht Perl hat. Hier ist auf jeden Fall eine von 5 Antworten, einige der anderen zeigen sed, wie man Perl benutzt ... ich habe gezeigt, wie man Perl benutzt ... ohne nach einem heiligen Krieg in dieser Angelegenheit zu suchen.
slm
1
@ DavidSainty Anscheinend nur OpenBSD. Ich glaube, ich habe die Annahme gemacht, dass die Open-Leute eher konservativ sind, was sie in der Basis zulassen. OpenBSD hat es definitiv in der Basis.
Kurtm
1
@slm: " Ich finde es extrem schwer, mir ein System vorzustellen, das Bash, aber nicht Perl hat. " Ich habe mehrere solcher Systeme auf meinem Schreibtisch. (Sie sind zufällig eingebettete Systeme.)
Keith Thompson
1

Einfach mit Bash

 while IFS= read -r line; do echo "foo" "${line}" ; done  < input > Output

Python verwenden

python -c "import sys; print 'foo '.join([ l for l in sys.stdin.readlines() ])" < input > Output

Wenn Sie direkt bearbeiten möchten

import fileinput
import sys

for line in fileinput.input(['inputfile'], inplace=True):
    sys.stdout.write('foo {l}'.format(l=line))

Referenzlink

Rahul Patil
quelle
Warum funktioniert es schneller als awk?
Rahul Patil
1
Es wird nur schneller funktionieren als awkbei sehr kleinen Dateien. Das Verhalten variiert je nach Echo-Implementierung, entfernt führende und nachfolgende Leerzeichen und verarbeitet Backslashes speziell.
Stéphane Chazelas
@StephaneChazelas Ja. Sie sind zu 100% korrekt, gerade getestet ... paste.ubuntu.com/6210934
Rahul Patil
prefix () { while IFS= read -r REPLY; do printf "%s%s\n" "$1" "$REPLY"; done; }sollte korrekter sein.
Matt
1
Warum das {}? Ich denke, @Matt hat vorgeschlagen, dass Sie es zu einer benannten Funktion machen. Was bringt es {}ohne einen Funktionsnamen?
Terdon
-1

Oder Sie können Folgendes tun:

vi filename.txt

Esc(um sicherzustellen, dass Sie sich im NORMALModus befinden), und geben Sie dann den folgenden Befehl ein:

:1,$ s/^/mystring
Dino
quelle
Da der Benutzer nach jeder Zeile der Datei fragt, können Sie diese durch 1,$ einfach ersetzen %. Dies macht den Befehl :%s/^/string/.
HalosGhost