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.