
ich wollte \n in einer Variablen erfassen (angenommen a) und $a vor dem Suchmuster in einer Datei (abc.txt) ersetzen.
kann mir jemand eine Lösung vorschlagen?
> cat abc.txt
hi how are you how is your health
> echo $a
\
erwartete Ausgabe ( Suchmuster - how
)
hi \
how are you \
how is your health
Antwort1
In einer Bourne-ähnlichen oder rc-ähnlichen Shell
a='
' perl -pe 's/pattern/$ENV{a}$&/g' < abc.txt
würde eine a
Umgebungsvariable an übergeben, die perl
ein Zeilenumbruchzeichen enthält, und perl
würde den Inhalt dieser Variablen vor jedem Vorkommen von pattern
im Inhalt von einfügen abc.txt
.
Um in Bourne-ähnlichen Shells ein beliebiges x
anderes Zeichen als eine Variable zuzuweisen , können Sie Folgendes verwenden:'
a='x'
Also für den Backslash:
a='\'
Für eine neue Zeile:
a='
'
Für Steuerzeichen wie Newline wäre das allerdings noch schlimmer, beispielsweise für Backspace oder Carriage-Return, da der Code dadurch allerdings unleserlicher wird.
ksh93 führte eine neue $'...'
Form von Anführungszeichen ein, um diese Zeichen in einer Escape-Form anzugeben. Andere Shells wie bash
, zsh
oder mksh
FreeBSD haben es seitdem sh
kopiert und erweitert (wie die $'\uXXXX'
von hinzugefügte Form ).zsh
In diesen Shells können Sie Folgendes verwenden:
a=$'\n' a=$'\b' a=$'\r' a=$'\\' a=$'\''
So weisen Sie ein Zeilenumbruch-, Rücktaste-, Wagenrücklauf-, Backslash- oder einfaches Anführungszeichen zu.
Dieser Anführungszeichenoperator ist noch nicht Standard, Sie können ihn also nicht in portablen sh
Skripten verwenden. Eine Standardalternative ist:
a=$(printf '\b')
für Backspace zum Beispiel, aber das funktioniert nicht für Newline, da die Befehlssubstitution ( $(cmd)
) nachfolgende Newline-Zeichen aus der Ausgabe von entfernt cmd
. Man muss auf Hacks wie diese zurückgreifen:
nl=$(printf '\n.'); nl=${nl%.}
(das heißt, ein hinzufügen .
und anschließend entfernen), um es beizubehalten.
Beachten Sie, dass perl
diese \n
Notationen auch in seinem Code verstanden werden, sodass Sie Folgendes tun können:
perl -pe 's/pattern/\n$&/g' < abc.txt
Die GNU-Implementierung von sed
(und heutzutage auch einige andere) unterstützt dies ebenfalls:
sed 's/pattern/\n&/g' < abc.txt
aber das ist nicht Standard. Normalerweise muss ein Zeilenumbruch im Ersetzungsteil des s
Befehls mit einem Backslash gefolgt von einem tatsächlichen Zeilenumbruch ausgedrückt werden, also wäre das:sed
backslash='\' newline='
'
sed "s/pattern/$backslash$newline&/g" < abc.txt
Oder ohne die Variablen:
sed 's/pattern/\
&/g' < abc.txt
Wenn Sie also sowohl einen Backslash als auch eine neue Zeile vor einfügen möchten pattern
, benötigen Sie:
sed 's/pattern/\\\
&/g' < abc.txt
Insgesamt 3 Backslashs, zwei für einen wörtlichen Backslash und einer für den Zeilenumbruch. Oder mit perl
:
perl -pe 's/pattern/\\\n$&/g' < abc.txt
Oder mit Ihrer a
Variable:
a='\
' perl -pe 's/pattern/$ENV{a}$&/g' < abc.txt
Antwort2
Sie können auch eigene Bash-Befehle verwenden mit:
cat abc.txt | sed -e 's/how/\nhow/g' | while read line; do echo "$line \\"; done