Fügen Sie nach dem angegebenen Muster mithilfe des Shell-Skripts mehrere Zeilen in eine Datei ein

74

Ich möchte mithilfe eines Shell-Skripts mehrere Zeilen in eine Datei einfügen. Betrachten wir den Inhalt meiner Eingabedatei als: input.txt:

abcd
accd
cdef
line
web

Jetzt muss ich vier Zeilen nach der Zeile 'cdef' in die Datei input.txt einfügen . Nach dem Einfügen sollte sich meine Datei folgendermaßen ändern:

abcd
accd
cdef
line1
line2
line3
line4
line
web

Die obige Einfügung sollte ich mit dem Shell-Skript machen. Kann mir jemand helfen?

user27
quelle

Antworten:

96

Ein anderer sed,

sed '/cdef/r add.txt' input.txt

input.txt:

abcd
accd
cdef
line
web

add.txt:

line1
line2
line3
line4

Prüfung:

sat:~# sed '/cdef/r add.txt' input.txt
abcd
accd
cdef
line1
line2
line3
line4
line
web

Wenn Sie die Änderungen in der input.txtDatei übernehmen möchten . Dann verwenden -imit sed.

sed -i '/cdef/r add.txt' input.txt

Wenn Sie einen regulären Ausdruck als Ausdruck verwenden möchten, müssen Sie das -ETag mit verwenden sed.

sed -E '/RegexPattern/r add.txt' input.txt
saß
quelle
Gibt es eine Möglichkeit, dies umgekehrt zu tun (entfernen Sie den in add.txt gefundenen Text aus input.txt)?
Sina
2
Eine Variante, die eine anonyme Datei ermöglicht, besteht darin, ein Here-Dokument in einen sed-Aufruf zu leiten und den rBefehl zum Lesen zu verwenden /dev/stdin.
Potong
Hallo, gibt es eine schnelle Möglichkeit, 4 Leerzeichen vor den hinzugefügten Zeilen von hinzuzufügen add.txt?
Hud
36

Verwenden von GNU sed:

sed "/cdef/aline1\nline2\nline3\nline4" input.txt

Wenn Sie angefangen haben mit:

abcd
accd
cdef
line
web

dies würde produzieren:

abcd
accd
cdef
line1
line2
line3
line4
line
web

Wenn Sie die Änderungen an der Datei direkt speichern möchten, sagen Sie:

sed -i "/cdef/aline1\nline2\nline3\nline4" input.txt
devnull
quelle
4
Ich bin neu in, sedaber wow, ich bin verliebt in seine Kraft! Wenn Sie zuerst eine leere neue Zeile anhängen möchten, müssen Sie das Backslash-Zeichen nach dem Befehl append wie folgt maskieren : sed "/cdef/a\\\nline1\nline2\nline3\nline4" input.txt. Ich bin mir nicht sicher, warum es so funktioniert, wenn jemand das erklären könnte, wäre das schön!
HDL
1
Der aktuelle Befehl fügt die Zeile * bei jeder Erwähnung von cdefein. Gibt es eine Möglichkeit, sie so zu gestalten, dass sie nur beim ersten Auftreten eingefügt wird cdefund nicht mehr?
CMCDragonkai
1
MacOS sedimplementiert den aBefehl nicht genau wie GNU sed, daher funktioniert das oben Gesagte unter MacOS ohne Mods nicht - zumindest ab MacOS 10.13 (siehe unix.stackexchange.com/a/131940/230763 )
Mike Lutz
24
sed '/^cdef$/r'<(
    echo "line1"
    echo "line2"
    echo "line3"
    echo "line4"
) -i -- input.txt
rindeal
quelle
Verpasste diese gute Antwort. Kürzer aber weniger lesbar ist sed '/^cdef$/r' <(printf "%s\n" line{1..4}) -i -- input.txt.
Walter A
16

Verwenden von awk:

awk '/cdef/{print $0 RS "line1" RS "line2" RS "line3" RS "line4";next}1' input.txt 

Erläuterung:

  • Sie finden die Zeile, die Sie einfügen möchten /.../
  • Sie drucken die aktuelle Zeile mit print $0
  • RSist eine integrierte awkVariable, die standardmäßig auf eingestellt ist new-line.
  • Sie fügen neue Zeilen hinzu, die durch diese Variable getrennt sind
  • 1Am Ende werden alle anderen Zeilen gedruckt. Wenn Sie " nextVorher verwenden" verwenden, können wir die aktuelle Zeile verhindern, da Sie sie bereits mit verwendet haben print $0.

$ awk '/cdef/{print $0 RS "line1" RS "line2" RS "line3" RS "line4";next}1' input.txt
abcd
accd
cdef
line1
line2
line3
line4
line
web

So nehmen Sie Änderungen an der Datei vor:

awk '...' input.txt > tmp && mv tmp input.txt
jaypal singh
quelle
1

Diese Antwort ist leicht zu verstehen

  • Kopieren Sie vor dem Muster
  • Fügen Sie Ihre Zeilen hinzu
  • Nach dem Muster kopieren
  • Ersetzen Sie die Originaldatei

    FILENAME = 'app / Providers / AuthServiceProvider.php'

SCHRITT 1 Kopie bis zum Muster

sed '/THEPATTERNYOUARELOOKINGFOR/Q' $FILENAME >>${FILENAME}_temp

SCHRITT 2 Fügen Sie Ihre Zeilen hinzu

cat << 'EOL' >> ${FILENAME}_temp

HERE YOU COPY AND
PASTE MULTIPLE
LINES, ALSO YOU CAN
//WRITE COMMENTS

AND NEW LINES
AND SPECIAL CHARS LIKE $THISONE

EOL

SCHRITT 3 Fügen Sie den Rest der Datei hinzu

grep -A 9999 'THEPATTERNYOUARELOOKINGFOR' $FILENAME >>${FILENAME}_temp

Ersetzen Sie die Originaldatei

mv ${FILENAME}_temp $FILENAME

Wenn Sie Variablen benötigen, ersetzen Sie in Schritt 2 'EOL' durch EOL

cat << EOL >> ${FILENAME}_temp

this variable will expand: $variable1

EOL
lalo
quelle
1

Hier ist eine generische Lösung auf @rindeal basierte Lösung , die auf MacOS / BSD nicht funktioniert ( /rerwartet eine Datei):

cat << DOC > input.txt
abc
cdef
line
DOC
$ cat << EOF | sed '/^cdef$/ r /dev/stdin' input.txt
line 1
line 2
EOF

# outputs:
abc
cdef
line 1
line 2
line

Dies kann verwendet werden, um an der angegebenen Position etwas in die Datei zu leiten:

$ date | sed '/^cdef$/ r /dev/stdin' input.txt

# outputs
abc
cdef
Tue Mar 17 10:50:15 CET 2020
line

Sie können auch mehrere Befehle hinzufügen, um die Markierungszeile zu löschen cdef:

$ date | sed '/^cdef$/ {
  r /dev/stdin
  d
}' input.txt

# outputs
abc
Tue Mar 17 10:53:53 CET 2020
line
Mana
quelle
0

Ich musste ein paar Dateien mit minimalem Werkzeugaufwand sed -e '/../r file.txtvorlegen, und für mich besteht das Problem oben darin, dass die Datei erst angehängt wird, nachdem der Rest des Spiels ausgedruckt wurde, und sie nicht ersetzt.

Dies ist nicht der Fall (alle Übereinstimmungen werden ersetzt und die Musterübereinstimmung wird an derselben Stelle fortgesetzt).

#!/bin/bash

TEMPDIR=$(mktemp -d "${TMPDIR:-/tmp/}$(basename $0).XXXXXXXXXXXX")
# remove on exit
trap "rm -rf $TEMPDIR" EXIT

DCTEMPLATE=$TEMPDIR/dctemplate.txt
DCTEMPFILE=$TEMPDIR/dctempfile.txt

# template that will replace
printf "0replacement
1${SHELL} data
2anotherlinenoEOL" > $DCTEMPLATE

# test data
echo -e "xxy \n987 \nxx xx\n yz yxxyy" > $DCTEMPFILE

# print original for debug
echo "---8<--- $DCTEMPFILE"
cat $DCTEMPFILE
echo "---8<--- $DCTEMPLATE"
cat $DCTEMPLATE
echo "---8<---"

# replace 'xx' -> contents of $DCTEMPFILE
perl -e "our \$fname = '${DCTEMPLATE}';" -pe 's/xx/`cat $fname`/eg' ${DCTEMPFILE}
Pasi Savolainen
quelle
0

Sie können awkzum Einfügen der Ausgabe eines Befehls in der Mitte von verwenden input.txt.
Die Zeilen eingefügt werden können den Ausgang eines sein cat otherfile, ls -loder 4 Zeilen mit einer Anzahl von erzeugten printf.

awk 'NR==FNR {a[NR]=$0;next}
    {print}
    /cdef/ {for (i=1; i <= length(a); i++) { print a[i] }}'
    <(printf "%s\n" line{1..4}) input.txt
Walter A.
quelle