Substitution von Umgebungsvariablen in sed


202

Wenn ich diese Befehle über ein Skript ausführe:

#my.sh
PWD=bla
sed 's/xxx/'$PWD'/'
...
$ ./my.sh
xxx
bla

es ist in Ordnung.

Aber wenn ich renne:

#my.sh
sed 's/xxx/'$PWD'/'
...
$ ./my.sh
$ sed: -e expression #1, char 8: Unknown option to `s' 

Ich habe in Tutorials gelesen, dass Sie zum Ersetzen von Umgebungsvariablen aus der Shell den $varnameTeil stoppen und "aus dem Anführungszeichen" setzen müssen, damit er nicht direkt ersetzt wird. Dies habe ich getan und funktioniert nur, wenn die Variable unmittelbar zuvor definiert wurde.

Wie kann ich sed dazu bringen, eine $varUmgebungsvariable zu erkennen , wie sie in der Shell definiert ist?


4
$ PWD enthält ein /, das den Ersatzbefehl beendet.
Derobert

@derobert: tnx. Eine der Lösungen adressiert dieses ...
RomanM

4
Verwenden Sie diese Option set -xin der Shell, damit die Shell jeden Befehl unmittelbar vor der Ausführung wiedergibt. Dies kann viel Verwirrung beseitigen. (Außerdem verwende ich oft set -u, um das De-Referenzieren von nicht gesetzten Variablen zu einem schweren Fehler zu machen. (Siehe set -eauch.))
Bobbogo

Ich hatte gehofft, einen Weg zu finden, wie sed mit den Umgebungsvariablen umgehen kann, um die Werte nicht in die Prozesstabelle zu verlieren. Es scheint, dass sed das falsche Werkzeug ist, um Geheimnisse gemäß allen Antworten in diesem Thread zu
installieren

Antworten:


302

Ihre beiden Beispiele sehen identisch aus, was die Diagnose von Problemen erschwert. Potenzielle Probleme:

  1. Möglicherweise benötigen Sie doppelte Anführungszeichen wie in sed 's/xxx/'"$PWD"'/'

  2. $PWDkann einen Schrägstrich enthalten. In diesem Fall müssen Sie ein Zeichen finden, das nicht in enthalten ist $PWD, um es als Trennzeichen zu verwenden.

Vielleicht, um beide Themen gleichzeitig zu lösen

sed 's@xxx@'"$PWD"'@'

Aber welches Zeichen kann ich dann verwenden, von dem ich sicher bin, dass es nicht in einem Pfadnamen erscheint?
RomanM

5
Sie können mehrere Kandidaten wie @ #% haben! und überprüfen Sie mit einem case-Ausdruck, ob $ PWD sie hat. ZB Fall "$ PWD" von @ ) ;; *) delim = "@" ;; esac; Wiederholen, bis $ delim nicht leer ist.
Norman Ramsey

Es gibt eine andere Alternative, anstatt doppelte Anführungszeichen zu verwenden. Siehe meine Antwort unten.
Thales Ceolin

Sie können ein anderes Trennzeichen für sed verwenden. Sie müssen nicht verwenden / können auch verwenden, wenn Ihre Umgebungsvariable eine URL ist.
Guchelkaben

123

Zusätzlich zu Norman Ramseys Antwort möchte ich hinzufügen, dass Sie die gesamte Zeichenfolge in doppelte Anführungszeichen setzen können (wodurch die Anweisung möglicherweise lesbarer und weniger fehleranfällig wird).

Wenn Sie also nach 'foo' suchen und durch den Inhalt von $ BAR ersetzen möchten, können Sie den Befehl sed in doppelte Anführungszeichen setzen.

sed 's/foo/$BAR/g'
sed "s/foo/$BAR/g"

In der ersten wird $ BAR nicht korrekt erweitert, während in der zweiten $ BAR nicht korrekt erweitert wird.


4
Dies ist sauberer als mit doppelten Anführungszeichen, einfachen Anführungszeichen usw.
herumzuspielen

Dies ist, was ich verwenden musste, um die Umgebungsvariable in diesem Befehl korrekt zu erweitern: sed -i "s / 127.0.0.1 / 127.0.0.1 localhost $ HOSTNAME /" hosts
izikandrw

2
Dies ist ordentlich, funktioniert aber nicht, wenn Sie komplexere Ersetzungen vornehmen möchten, z. B. "2,$s/^/$foo/"wenn diese $sauch als Variable interpretiert werden und dies nicht sollte.
MJP

59

Sie können neben "/" auch andere Zeichen als Ersatz verwenden:

sed "s#$1#$2#g" -i FILE

In meinem speziellen Fall war $ 2 ein Dateipfad, ebenso sedwie Barfing aufgrund der Interpretation /des Inhalts von $ 2. Dies war genau das, was ich brauchte, um daran vorbei zu kommen. Danke für einen tollen Tipp!
Boyd Hemphill

54

Eine weitere einfache Alternative:

Da $PWDnormalerweise ein Schrägstrich enthalten ist /, verwenden Sie |anstelle von /für die sed-Anweisung:

sed -e "s|xxx|$PWD|"

4
Sie sagten "eine Alternative zur Verwendung von doppelten Anführungszeichen" und doch verwendet Ihr Beispiel doppelte Anführungszeichen?
Jeach

Ich denke, der Punkt ist, dass es keine doppelten Anführungszeichen direkt um $PWD... verwendet?
Christian

14

Mit Ihrer Frage bearbeiten sehe ich Ihr Problem. Angenommen, das aktuelle Verzeichnis lautet /home/yourname ... in diesem Fall der folgende Befehl:

sed 's/xxx/'$PWD'/'

wird erweitert auf

sed `s/xxx//home/yourname//

das ist nicht gültig. Sie müssen in Ihrem $ PWD \vor jedem einen Charakter setzen, /wenn Sie dies tun möchten.


aber PWD wird durch die Shell definiert ... wenn ich Echo $ PWD gehe, bekomme ich das pwd
RomanM

1
Wie entkommen Sie den Umgebungsvariablen?
Einpoklum

1
Die ausgewählte Antwort beschreibt eine Problemumgehung ... Verwenden Sie keinen Schrägstrich für das Trennzeichen
Eddie

Dies wird zu einem Problem, sobald Ihr aktuelles Arbeitsverzeichnis dieses andere Zeichen enthält.
Blubberdiblub

6

schlechter Weg: Trennzeichen ändern

sed 's/xxx/'"$PWD"'/'
sed 's:xxx:'"$PWD"':'
sed 's@xxx@'"$PWD"'@'

vielleicht sind das nicht die endgültige Antwort,

Sie können nicht bekannt , welche Zeichen auftreten in wird $PWD, / :OR @.

Der gute Weg ist, das Sonderzeichen in zu ersetzen $PWD.

Guter Weg: Fluchttrennzeichen

Zum Beispiel: Versuchen Sie, URLals $ url zu ersetzen (hat : /im Inhalt)

x.com:80/aa/bb/aa.js

in string $ tmp

<a href="URL">URL</a>

ein. Verwendung /als Trennzeichen

echo ${url//\//\\/}
x.com:80\/aa\/bb\/aa.js

echo ${url//\//\/}
x.com:80/aa/bb/aa.js

echo "${url//\//\/}"
x.com:80\/aa\/bb\/aa.js

echo $tmp | sed "s/URL/${url//\//\\/}/"
<a href="x.com:80/aa/bb/aa.js">URL</a>

echo $tmp | sed "s/URL/${url//\//\/}/"
<a href="x.com:80/aa/bb/aa.js">URL</a>

ODER

b. Verwendung :als Trennzeichen (besser lesbar als /)

echo ${url//:/\:}
x.com:80/aa/bb/aa.js

echo "${url//:/\:}"
x.com\:80/aa/bb/aa.js

echo $tmp | sed "s:URL:${url//:/\:}:g"
<a href="x.com:80/aa/bb/aa.js">x.com:80/aa/bb/aa.js</a>

3

Tatsächlich ist es am einfachsten (zumindest in gnu sed), ein anderes Trennzeichen für den Befehl sed substitution (s) zu verwenden. Anstatt also s / pattern / '$ mypath' / zu s / pattern // my / path / zu erweitern, was natürlich den Befehl s verwirrt, verwenden Sie s! Pattern! '$ Mypath'! welches zu s! pattern! / my / path! Ich habe den Bang (!) -Zeichen (oder alles, was Sie möchten) verwendet, der den üblichen Schrägstrich als Trennzeichen vermeidet, aber keineswegs Ihre einzige Wahl ist.


3
VAR=8675309
echo "abcde:jhdfj$jhbsfiy/.hghi$jh:12345:dgve::" |\
sed 's/:[0-9]*:/:'$VAR':/1' 

Dabei enthält VAR, durch was Sie das Feld ersetzen möchten


3

Umgang mit VARIABLEN innerhalb von sed

[root@gislab00207 ldom]# echo domainname: None > /tmp/1.txt

[root@gislab00207 ldom]# cat /tmp/1.txt

domainname: None

[root@gislab00207 ldom]# echo ${DOMAIN_NAME}

dcsw-79-98vm.us.oracle.com

[root@gislab00207 ldom]# cat /tmp/1.txt | sed -e 's/domainname: None/domainname: ${DOMAIN_NAME}/g'

 --- Below is the result -- very funny.

domainname: ${DOMAIN_NAME}

 --- You need to single quote your variable like this ... 

[root@gislab00207 ldom]# cat /tmp/1.txt | sed -e 's/domainname: None/domainname: '${DOMAIN_NAME}'/g'


--- The right result is below 

domainname: dcsw-79-98vm.us.oracle.com

Ich hatte Probleme, dies in Azure DevOps YAML-Pipelines zum Laufen zu bringen. Dieser Kommentar hat mir geholfen, diesen Trick erfolgreich zum Tokenisieren einiger Konfigurationsdateien zu verwenden.
Andov

1

Ich hatte ein ähnliches Problem, ich hatte eine Liste und ich muss ein SQL-Skript basierend auf einer Vorlage erstellen (die @INPUT@als zu ersetzendes Element enthalten ist ):

for i in LIST 
do
    awk "sub(/\@INPUT\@/,\"${i}\");" template.sql >> output
done
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.