Sed'de ortam değişken ikamesi


202

Bu komutları bir komut dosyasından çalıştırırsam:

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

iyi.

Ama eğer koşarsam:

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

Ortam değişkenlerini kabuktan değiştirmek için durdurmanız gerektiğini ve $varnamedoğrudan dışarıda yer değiştirmemesi için parçayı 'alıntı' yapmanız gerektiğini okudum, yaptığım şey bu ve sadece değişken daha önce tanımlanmışsa çalışır.

Bir $varkabuğu kabukta tanımlandığı gibi bir ortam değişkeni olarak tanımak için nasıl sed alabilirim ?


5
$ PWD, substitute komutunu sonlandıran bir / içerir.
derobert

@derobert: tnx. Çözümlerden biri bunu ele alıyor ...
RomanM

4
Kullan set -xonları çalıştırır hemen önce her komutu echo shell almak için kabukta. Bu çok fazla karışıklığa neden olabilir. (Ayrıca, sık sık tanımlanmamış set -udeğişkenleri referans yapmak için de kullanıyorum . (Ayrıca bkz set -e.))
bobbogo 15:02

Sed için ortam değişkenlerini işlem tablosuna sızdırmamak için bir yol bulmayı umuyordum, sed, bu
konudaki

Yanıtlar:


305

İki örneğiniz aynı görünüyor ve bu da sorunların teşhis edilmesini zorlaştırıyor. Potansiyel sorunlar:

  1. Olduğu gibi çift tırnaklara ihtiyacınız olabilir sed 's/xxx/'"$PWD"'/'

  2. $PWDBir karakteri bulmalıyız bu durumda bir çizgi içerebilir değil içerdiği $PWDayırıcı olarak kullanılması ile ilgilidir.

Her iki sorunu da aynı anda çivilemek, belki

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

ama, o zaman eminim hangi karakter yol adında görünmeyeceğini biliyorum?
RomanM

5
@ #% Gibi birkaç adayınız olabilir! ve $ PWD'de bunlara sahip olup olmadığını öğrenmek için bir vaka ifadesine bakın. Örneğin, vaka arasında "$ PWD" @ ) ;; *) sınır = "@" ;; esac; $ delim boş olmayana kadar tekrarlayın.
Norman Ramsey

Çift tırnak kullanmak yerine başka bir alternatif daha var. Benim Bkz cevabı aşağıda.
Thales Ceolin

Sed için başka bir sınırlayıcı kullanabilirsiniz. Ortam değişkeniniz bir URL ise, kullanmanız gerekmez / kullanabilirsiniz.
Guchelkaben

126

Norman Ramsey'in cevabına ek olarak, tüm dizeyi (alıntıyı daha okunaklı ve daha az hataya eğilimli hale getirebilir) iki kez teklif edebileceğinizi eklemek isterim.

Eğer 'foo' kelimesini aramak ve $ BAR içeriğiyle değiştirmek istiyorsanız sed komutunu çift tırnak içine alabilirsiniz.

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

İlkinde, $ BAR doğru şekilde genişlemeyken, ikinci $ BAR'da doğru genişleyecektir.


4
Bu çift tırnak, tek tırnak vb ile
uğraşmak

Bu komutta ortam değişkenini doğru bir şekilde genişletmek için kullanmam gereken şey buydu: sed -i "s / 127.0.0.1 / 127.0.0.1 localhost $ HOSTNAME /" hosts
izikandrw

2
Bu temiz ama gibi bazı daha karmaşık alternatifler, yapmak istediğim zaman çalışmıyor "2,$s/^/$foo/"olarak $sçok bir değişken olarak yorumlanır alır ve bu olmamalıdır.
mjp

59

Bunun yerine "/" dışında başka karakterler de kullanabilirsiniz:

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

Benim özel durumumda, 2 $ bir dosya sedyoluydu , bu yüzden /2 $ 'ın içeriğinde yorumlanması nedeniyle engelleme yapıldı. Bu tam olarak geçmek için gereken şeydi. Teşekkürler fora büyük ipucu!
Boyd Hemphill

54

Başka bir kolay alternatif:

Yana $PWDgenellikle çizgi içerecektir /kullanmak |yerine /sed ifadesi için:

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

4
"Çift tırnak kullanmaya alternatif" dediniz, ancak örnekte çift tırnak kullanılıyor mu?
14'e

Demek istediğim bu doğrudan çift tırnak kullanmıyor $PWD...?
Christian

14

Sorunuz düzenlendikten sonra sorununuzu görüyorum. Diyelim ki mevcut dizin /home/yourname ... bu durumda aşağıdaki komutunuz:

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

genişleyecek

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

bu geçerli değil. Bunu yapmak için $ PWD'nizde \her birinin önüne bir karakter koymanız gerekir /.


ama PWD kabuk tarafından tanımlanır ... eğer echo $ PWD giderseniz ben pwd olsun
RomanM

1
Peki, çevre değişkenlerinden nasıl kaçıyorsunuz?
einpoklum

1
Seçilen cevap bir geçici çözümü açıklıyor ... ayırıcı için eğik çizgi kullanmayın
Eddie

Geçerli çalışma dizininiz o diğer karakteri içerdiğinde sorun olur.
blubberdiblub

6

kötü yol: sınırlayıcıyı değiştir

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

belki son cevap olmayanlar,

hangi karakterin meydana geleceğini bilemezsiniz $PWD, / :VEYA@ .

iyi yol yerine özel karakteri değiştirmektir $PWD.

iyi yol: kaçış sınırlayıcı

örneğin: URL$ url olarak değiştirmeyi deneyin ( : /içerik var)

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

$ tmp dizesinde

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

a. /sınırlayıcı olarak kullan

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>

VEYA

b. :sınırlayıcı olarak kullanın (daha okunabilir /)

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

Aslında, en basit şey (en azından gnu sed'de) sed yerine koyma (lar) komutu için farklı bir ayırıcı kullanmaktır. Dolayısıyla s / pattern / '$ mypath' / yerine s / pattern // my / path / dizinine genişletilmek yerine, s komutunu karıştıracak, s! Pattern! '$ Mypath' kullanın! ki bu!! desen! / benim / yol! Ben ayırıcı olarak her zamanki gibi, ama-sadece-hiç-sadece-seçim-ön eğik çizgi önler bang (!) Karakter (veya istediğiniz bir şey kullanın) kullandım.


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

burada VAR, alanı değiştirmek istediğiniz şeyi içerir


3

Sed içinde VARIABLES ile başa çıkmak

[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

Bunu Azure DevOps YAML boru hatlarında çalıştırmak için uğraşıyordum. Bu yorum, bazı yapılandırma dosyalarını belirtmek için bu hileyi başarıyla kullanmama yardımcı oldu.
andov

1

Ben benzer bir sorun vardı, bir liste vardı ve şablon (bu @INPUT@değiştirilecek öğe olarak içeren) dayalı bir SQL komut dosyası oluşturmak zorunda:

for i in LIST 
do
    awk "sub(/\@INPUT\@/,\"${i}\");" template.sql >> output
done
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.