Bir sed ikamesinin LHS ve RHS değişkenlerini nasıl kullanabilirim?


61

Ben yapmak istiyorum:

cat update_via_sed.sh | sed 's/old_name/new_name/' > new_update_via_sed.sh

programımda

Fakat değişkenleri kullanmak istiyorum, örneğin

old_run='old_name_952'
new_run='old_name_953'

Onları kullanmayı denedim ama oyuncu değişikliği olmadı (hata yok). Denedim:

cat update_via_sed.sh | sed 's/old_run/new_run/'
cat update_via_sed.sh | sed 's/$old_run/$new_run/'
cat update_via_sed.sh | sed 's/${old_run}/${new_run}/'

2
Yanıtı, komut bağımsız değişkeninde Parametre kullan bölümünde bulabilirsiniz .
Manatwork

Yanıtlar:


45

Yapabilirsin:

sed "s/$old_run/$new_run/" < infile > outfile

Ancak $old_runbunun normal bir ifade olarak alınacağına ve bu yüzden değişkenin içerdiği /veya kaçması. gereken özel karakterlerin alınmasına dikkat edin . Benzer şekilde, içinde , ve karakterler özel olarak tedavi edilmesi gerekir ve kaçmak zorunda kalacak o ve yeni satır karakterleri.$new_run&\/

Eğer içeriği sizin kontrolünüz altındaysa $old_runya $new_runda kontrolünüz altında değilse, bu kaçmayı ya da aksi halde bu kodun kod ekleme güvenlik açığı anlamına gelmesi çok önemlidir .


3
Tek paragrafta sed params kullanıyordum, çift tırnak kullandım ve dosya çalıştı. Muhteşem.
Aakash

ondan değil sednormal ifadeler kullanabilirsiniz olmaz yalnız ama sed -Eolur?
Kiwy

@Kiwy, hayır. e xpression-e belirtmek içindir , böylece birden fazla ( içeride ) veya dosya ve ifadelerin kombinasyonlarını () geçirebilirsiniz . Bazı uygulamalarda, BRE'ler yerine ERE'lerin kullanılmasını söyleyenleri kafa karıştırıcı olabilir . sed sed -e exp1 -e exp2sed -f file -e exp-E
Stéphane Chazelas

Yanlış yazdım, ancak tamam, neden -Enormalde değil de sadece genişletilmiş regex'te ustalaşmadan sed'i kullanmada bu kadar çok sorunum olduğunu açıklıyor . Açıklama için teşekkürler.
Kiwy

@Kiwy, ayrıca daha düzenli ifade sözdizimleri için bazı uygulamalar tarafından desteklenen daha fazla seçenek için bağlantılı soru ve cevaplara bakın sed.
Stéphane Chazelas

31

Bu çalıştı:

cat update_via_sed.sh | sed 's/'"$old_run"'/'"$new_run"'/'

Aynı dosyayı tekrar kullanmak istediğim için, bunu benzer bir yaklaşım isteyen herkes için kullanıyorum:

cat update_via_sed.sh | sed 's/'"$old_run"'/'"$new_run"'/' > new_update; mv -f new_update update_via_sed.sh

Yukarıdaki yeni bir dosya oluşturdu, ardından geçerli dosyayı, yeni dosyayı geçerli dosya olarak yeniden adlandırmak yerine siler.


4
Özel karakterlere sahip olmadığınız sürece, kedi, mv veya fazladan '' gerekmez. Yani bu sed -i s/"$old"/"$new"/ update_via_sed.sh. Ancak bunun eski ve yeninin hiçbir değeri için işe yaramadığını unutmayın. Örneğin, $ old hala bir arama olduğundan ve $ new bazı karakterlerin özel anlamlara sahip olduğu bir değiştirme şekli olduğundan / etc içermemelidir.
frostschutz

1
sed -i "s/$old/$new/"de tamam (yukarıdaki önlemlerle birlikte). sedgenellikle ayırıcıyı skomuttan sonraki ilk karakter olarak kabul eder - yani değişkenleriniz eğik çizgiler içeriyorsa /ancak ( @) ifadesinde yazmıyorsa , "s @ $ old @ $ new @" kullanabilirsiniz.
Peterph

22

Değişkenleri sed'de, çift bir alıntıda olduğu sürece (tek bir alıntı değil) kullanabilirsiniz:

sed "s/$var/r_str/g" file_name >new_file

/Değişkende eğik çizgi ( ) varsa, aşağıdaki gibi farklı bir ayırıcı kullanın.

sed "s|$var|r_str|g" file_name >new_file

1
Çift tırnak kullanmaya ihtiyaç duyduğundan bahsetmek için +1. Bu benim sorunumdu.
speckledcarp

1
Tam olarak ne ben kullanımı dahil, arıyordu |benim durumumda olduğu gibi sahip olduğu, böylece değişkenler yolu içerir /İçinde
yorch

Bazı boru nedenlerden dolayı |MacOS 10.14 benim için çalıştı, ama gibi diğer seperatörler @veya #değil. Benim env var de ileri eğik çizgiler vardı.
davidenke

21

'yerinde' sed (-i bayrağını kullanarak) cevaptı. Peterph'e teşekkürler.

sed -i "s@$old@$new@" file

2
Tırnaklar yanlış yerde. tırnak, değişkenler etrafında olmalıdır, s@(kabuğa hiçbir şekilde özel değildir). En iyisi, her şeyi gibi tırnak içine koymaktır sed -i "s@$old@$new@" file. Bunun -istandart bir sedseçenek olmadığını unutmayın .
Stéphane Chazelas

$Bu komutta nasıl kaçabilirim ? Gibi, ben $xxxbir değişkenin değerini bir bütün olarak değiştireceğim $JAVA_HOME. Denedim sed -i "s@\$xxx@$JAVA_HOME@" file, ama hata diyorno previous regular expression
hakunami

3

man bash bu tek alıntı hakkında verir

Karakterleri tek tırnak işaretleri içine alma, tırnak içindeki her karakterin gerçek değerini korur. Önceden ters eğik çizgiden önce olsa bile, tek tırnaklar arasında tek bir teklif oluşmayabilir.

Komut satırına ne yazarsanız yazın, bash bunu yorumlar ve sonucu gönderilmesi gereken programa gönderir. Bu durumda eğer kullanırsanız sed 's/$old_run/$new_run/', bash ilk önce sedonu görür, $PATHdeğişkende mevcut bir çalıştırılabilir olarak tanır. . sedYürütülebilir bir girişi gerektirir. Bash girişi arar ve bulur 's/$old_run/$new_run/'. Tek tırnak, bash’ın içindeki içeriği yorumlamamasını ve olduğu gibi geçirmemesini söylüyor. Öyleyse, bash onları sedye'ye geçirir Sed bir hata veriyor çünkü $sadece satırın sonunda meydana gelebiliyor.

Bunun yerine eğer çift tırnak kullanırsak, yani "s/$old_run/$new_run/"bash bunu görür ve $old_rundeğişken bir isim olarak yorumlanır ve bir ikame yapar (bu aşama değişken genişleme olarak adlandırılır). Gerçekten de ihtiyacımız olan şey bu.

Ancak, çift tırnak işareti kullanırken dikkatli olmalısınız, çünkü önce bash ile yorumlanır ve sonra sed'e verilir. Bu nedenle, `gibi bazı semboller kullanmadan önce kaçmalıdır.


1

Saygısız olma riski - düşündün mü perl.

Diğer şeylerin yanı sıra, 'sed style' işlemleri yapmakta oldukça iyidir, ancak aynı zamanda daha tam özellikli bir programlama sorunu da vardır.

Örneğinize benziyor , aslında yapmaya çalıştığınız şey bir sayıyı arttırmak.

Peki ya:

#!/usr/bin/env perl
use strict;
use warnings 'all'; 

while ( <DATA> ) {
    s/old_name_(\d+)/"old_name_".($1+1)/e;
    print;
}

__DATA__
old_name_932

veya tek bir astar olarak - sed tarzı:

perl -pe 's/old_name_(\d+)/"old_name_".($1+1)/e'

1
$ echo $d1 | sed -i 's/zkserver1/'${d1}'/g' deva_file
sed: -e expression #1, char 26: unterminated `s' command 

Gelen $d1ı değerlerini depolamak am

Değeri değişkenden değiştiremiyorum, bu yüzden aşağıdaki komutu çalıştırdım.

echo $d1 | sed -i 's/zkserver1/'"${d1}"'/g' deva_file

çift ​​tırnak işareti eksik "${d1}", hataydı


-2

Varsayılan $old_runve $new_runönceden ayarlanmış:

cat update_via_sed.sh | eval $(print "sed 's/$old_run/$new_run/g'")

Bu ekranda değişikliği gösterir. Gerekirse çıktıyı dosyaya yönlendirebilirsiniz.


-2

Sed içindeki bir değişkeni kullanmak için, kullandığınız düzende değişkeni içine almak için "" çift tırnak işaretini kullanın. Örneğin: a = "Merhaba" 'a' değişkenini bir desene eklemek istiyorsanız, aşağıdakileri kullanabilirsiniz: sed -n "1, / pattern" $ {a} "pattern / p" dosyaadı


2
$aBurada genişlemesi belirtilmez, bu, değerindeki herhangi bir boşluğun kabukta sözcük bölmeye neden olacağı anlamına gelir.
Kusalananda

-2

Ayrıca Perl kullanabilirsiniz:

perl -pi -e ""s/$val1/$val2/g"" file

Değerlerinde boşluk olabilecek değişkenleri göz önünde bulundurun. Perl ifadesinin ( "") etrafındaki boş dizeler hiçbir şey yapmaz.
Kusalananda

-2

dizeyi kır

bad => linux $ old_run dizgisine bakınız:

sed 's/$old_run/$new_run/'

good => linux $ old_run değişkenine bakın:

sed 's/'$old_run'/'$new_run'/'

1
Ve eğer $old_runveya $new_runboşluklar içeriyorsa?
Kusalananda
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.