Voeg meerdere regels in een bestand in na gespecificeerd patroon met behulp van shellscript

Ik wil meerdere regels in een bestand invoegen met behulp van shellscript.
Laten we eens kijken naar de inhoud van mijn invoerbestand:
input.txt:

abcd
accd
cdef
line
web

Nu moet ik vier regels invoegen na de regel ‘cdef’ in het bestand input.txt.
Na het invoegen zou mijn bestand als volgt moeten veranderen:

abcd
accd
cdef
line1
line2
line3
line4
line
web

De bovenstaande invoeging zou ik moeten doen met behulp van het shellscript. Kan iemand me helpen?


Antwoord 1, autoriteit 100%

Nog een sed,

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

input.txt:

abcd
accd
cdef
line
web

add.txt:

line1
line2
line3
line4

Testen:

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

Als u de wijzigingen in het bestand input.txtwilt toepassen. Gebruik vervolgens -imet sed.

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

Als je een regex als expressie wilt gebruiken, moet je de tag -Egebruiken met sed.

sed -E '/RegexPattern/r add.txt' input.txt

Antwoord 2, autoriteit 40%

GNU sedgebruiken:

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

Als je bent begonnen met:

abcd
accd
cdef
line
web

dit zou het volgende opleveren:

abcd
accd
cdef
line1
line2
line3
line4
line
web

Als u de wijzigingen in het bestand ter plaatse wilt opslaan, zegt u:

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

Antwoord 3, autoriteit 25%

sed '/^cdef$/r'<(
    echo "line1"
    echo "line2"
    echo "line3"
    echo "line4"
) -i -- input.txt

Antwoord 4, autoriteit 17%

Gebruik awk:

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

Uitleg:

  • Je vindt de regel die je wilt invoegen met /.../
  • U drukt de huidige regel af met print $0
  • RSis een ingebouwde awk-variabele die standaard is ingesteld op new-line.
  • Je voegt nieuwe regels toe, gescheiden door deze variabele
  • 1aan het einde resulteert in het afdrukken van elke andere regel. Door nextte gebruiken voordat het ons in staat stelt om de huidige regel te voorkomen, omdat je het al hebt afgedrukt met 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

Om wijzigingen in het bestand aan te brengen, kunt u het volgende doen:

awk '...' input.txt > tmp && mv tmp input.txt

Antwoord 5, autoriteit 5%

Hier is een meer algemene oplossing gebaseerd op @rindeal oplossingdie niet werkt op MacOS/BSD (/rverwacht een bestand):

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

Dit kan worden gebruikt om alles op de gegeven positie in het bestand te pipen:

$ date | sed '/^cdef$/ r /dev/stdin' input.txt
# outputs
abc
cdef
Tue Mar 17 10:50:15 CET 2020
line

U kunt ook meerdere opdrachten toevoegen waarmee u de markeringsregel cdef:

kunt verwijderen

$ date | sed '/^cdef$/ {
  r /dev/stdin
  d
}' input.txt
# outputs
abc
Tue Mar 17 10:53:53 CET 2020
line

Antwoord 6

Dit antwoord is gemakkelijk te begrijpen

  • Kopieer vóór het patroon
  • Voeg je regels toe
  • Kopieer naar het patroon
  • Origineel bestand vervangen

    FILENAME=’app/Providers/AuthServiceProvider.php’

STAP 1 kopiëren tot het patroon

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

STAP 2 voeg je regels toe

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

STAP 3 voeg de rest van het bestand toe

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

VERVANG origineel bestand

mv ${FILENAME}_temp $FILENAME

als je variabelen nodig hebt, vervang dan in stap 2 ‘EOL’ door EOL

cat << EOL >> ${FILENAME}_temp
this variable will expand: $variable1
EOL

Antwoord 7

Ik moest een paar bestanden sjablonen met minimale tooling en voor mij is het probleem met bovenstaande sed -e '/../r file.txtdat het het bestand alleen toevoegt nadat het is afgedrukt de rest van de wedstrijd, vervangt het hem niet.

Dit doet het niet (alle overeenkomsten worden vervangen en patroonovereenkomst gaat verder vanaf hetzelfde punt)

#!/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}

Antwoord 8

Je kunt awkgebruiken om de uitvoer van een commando in het midden van input.txtin te voegen.
De in te voegen regels kunnen de uitvoer zijn van een cat otherfile, ls -lof 4 regels met een nummer gegenereerd door 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

Antwoord 9

Als je dat met een bash-script wilt doen, is dat handig.

echo $password | echo 'net.ipv4.ping_group_range=0 2147483647' |  sudo -S tee -a /etc/sysctl.conf

Other episodes