Eğik çizgi içeren bir değişken sed'e nasıl geçirilir


102

Eğik çizgi içeren bir değişkeni şablon olarak nasıl geçirirsiniz sed?

Örneğin, aşağıdaki değişkene sahipsem:

var="/Users/Documents/name/file"

Bunu şu şekilde geçirmek istiyorum sed:

sed "s/$var/replace/g" "$file"

Ancak hata alıyorum. Sorunu nasıl aşabilirim?

Yanıtlar:


197

sedHerhangi bir sınırlayıcıyı ( kontrol karakterleri dahil ) kullanmanıza olanak tanıyan alternatif bir normal ifade sınırlayıcı kullanın :

sed "s~$var~replace~g" $file

2
Çalışmıyor. Sed -i "s ~ blah ~ $ var ~ g dosyasını" deneyip şunu alıyorum: "sed -e expression # 1, char 70: sonlandırılmamış" s 'command ". Suçlunun $ var cinsinden bir eğik çizgi olduğunu doğruladım. Buna yönelik bu çözümün çeşitleri her yerde ve hiçbiri işe yaramıyor. Sed yakın zamanda güncellendi mi? Ubuntu 14.04.4 LTS üzerinde v4.2.2 kullanıyorum.
Paul Ericson

Bu, değerinin ne olduğuna bağlı$var
anubhava

1
@PaulEricson'ın gözlemlediği gibi ~ ile çalışmıyor, ancak yine de |
Kenny Ho

1
Son "~" (g'den sonra), en azından AWS Amazon Linux için (CentOS tabanlı) gerekli görünmüyor
Saúl Martínez Vidals


63

Saf bir bash yanıtı: değişkendeki eğik çizgilerden ters eğik çizgi-kaçış yapmak için parametre genişletmesini kullanın:

var="/Users/Documents/name/file"
sed "s/${var//\//\\/}/replace/g" $file

1
Bu iyi bir yoldur, çünkü hangi karakterlerin değişkeni içerdiğini her zaman bilemezsiniz. Böylece, bir şüpheniz varsa, sed sınırlayıcıdan her zaman kaçabilirsiniz. Örneğin: sed "s: $ {var //: / \\:}: replace: g" $ dosya
Stephane L

Güzel. Bazı yeniden adlandırma komut dosyalarımı çok daha temiz hale getirdi.
Cloud

Bugün güzel bir şey öğrendim, teşekkürler. Kabul edilen cevap olmalı.
Steve Kehlet

6
Desen varlık Bazı netlik burada kullandı: ${parameter/pattern/string}. Dolayısıyla, bu durumda, parametre şudur var, modeldir /\/ve dize olur \\/. Çoğaltma bir ile başladığından, çoğaltmanın tüm örnekleri değiştirilir /.
Josh

1
@josh, ve bu nedenle, desenin baştaki eğik çizgisi aslında değiştirilecek desenin bir parçası değildir.
glenn jackman

32

Bunu yapmanın başka bir yolu, anubhava'nın cevabından daha çirkin olsa da, varbaşka bir sedkomut kullanarak tüm ters eğik çizgilerden kaçmaktır :

var=$(echo "$var" | sed 's/\//\\\//g')

o zaman bu çalışacaktır:

sed "s/$var/replace/g" $file

12

/Sed'de sınırlayıcı olarak kullanılması , değiştirildiğinde değişkendeki eğik çizgi ile çelişir ve sonuç olarak bir hata alırsınız. Bunu aşmanın bir yolu, o değişkendeki herhangi bir karakterden benzersiz olan başka bir sınırlayıcı kullanmaktır.

var="/Users/Documents/name/file"

duruma uygun oktotorp karakterini (veya /kullanım kolaylığı sağlamayan herhangi bir karakteri ) kullanabilirsiniz.

sed "s#$var#replace#g" 

veya

sed 's#$'$var'#replace#g'

bu, değişken boşluk içermediğinde uygundur

veya

sed 's#$"'$var'"#replace#g'

Yukarıdakileri kullanmak daha akıllıca olacaktır, çünkü kabuğunuzun kabuğa özel bir kabuk karakteri olarak kabul edilebilecek herhangi bir karakteri yorumlamasına neden olabilecek tüm komutu çift tırnak içine almakla karşılaştırıldığında, yalnızca o değişkendeki her şeyi değiştirmekle ilgileniyoruz.


Çalışmıyor. Sed -i "s ~ blah ~ $ var ~ g dosyasını" deniyorum ve şunu alıyorum: "sed -e expression # 1, char 70: sonlandırılmamış" s 'command ". Suçlunun $ var cinsinden bir eğik çizgi olduğunu doğruladım. Buna yönelik bu çözümün çeşitleri her yerde ve hiçbiri işe yaramıyor. Sed yakın zamanda güncellendi mi? Ubuntu 14.04.4 LTS üzerinde v4.2.2 kullanıyorum.
Paul Ericson

@PaulEricson Bunu kullanabileceğim herhangi bir Ubuntu'da yeniden yayınlayamıyorum. Eğer $variçeriğiniz ~varsa, açıkça farklı bir sınırlayıcı seçmeniz gerekecektir. "Sonlandırılmamış" hatası, sizin $varyeni satır içeriyormuş gibi geliyor ; Ters eğik çizgi ile değerdeki her satırdan kaçarak düzeltebilirsiniz, ancak bunun tamamen taşınabilir olduğunu düşünmüyorum. Bu, değerdeki eğik çizgi sorunuyla büyük ölçüde ilgisizdir.
üçlü

@PaulEricson Oh ve alıntılarınız yanlış, tırnak içinde dosya adını yazmamalısınız. sed -i "s~blah~$var~g" filesadece gerçek sedmetnin etrafındaki tırnak işaretleriyle .
üçlü

5

Bu eski bir sorudur, ancak buradaki cevapların hiçbiri, s/from/to/çok fazla ayrıntı dışında operasyonları tartışmaz .

Bir sedifadenin genel şekli

*address* *action*

burada adres bir normal ifade aralığı veya bir satır numarası aralığı olabilir (veya boş, bu durumda eylem her giriş satırına uygulanır). Yani mesela

sed '1,4d' file

1'den 4'e kadar olan satırları silecektir ( adres , satır numarası aralığıdır 1,4ve eylem , dsilme komutudur); ve

sed '/ick/,$s/foo/bar/' file

, normal ifadedeki ilk eşleşme ile dosyanın sonu arasındaki herhangi bir satırda ilk geçtiği yeri fooile değiştirir ( adres aralıktır ve eylem , ikame komutudur ).barick/ick/,$ss/foo/bar/

Bu bağlamda, ickbir değişkenden geldiyse,

sed "/$variable/,\$s/foo/bar/"

(Kabuğun değişkeni enterpolasyon yapabilmesi için tek yerine çift tırnak kullanıldığına ve dolar işaretini çift tırnak içine alma gerekliliğine dikkat edin) ancak değişken bir bölü çizgi içeriyorsa, sözdizimi hatası alırsınız. (Kabuk değişkeni genişletir, sonra elde edilen dizgeyi iletir sed; bu nedenle sedyalnızca değişmez metni görür - kabuğun değişkenleri hakkında hiçbir kavramı yoktur.)

Çözüm, farklı bir sınırlayıcı kullanmaktır (tabii ki değişkenin değerinde bulunamayan bir karakteri kullanabilmeniz gerekir), ancak s%foo%bar%durumdan farklı olarak, farklı bir sınırlayıcı kullanmak istiyorsanız, sınırlayıcıdan önce bir ters eğik çizgiye de ihtiyacınız vardır. varsayılandan daha fazla sınırlayıcı /:

sed "\\%$variable%,\$s/foo/bar/" file

(tek tırnak içinde, tek bir ters eğik çizgi yeterli olacaktır); veya değerdeki her bölü çizgisinden ayrı ayrı kaçabilirsiniz. Bu belirli sözdizimi yalnızca Bash'tir:

sed "/${variable//\//\\/}/,\$s/foo/bar/" file

veya farklı bir kabuk kullanıyorsanız, deneyin

escaped=$(echo "$variable" | sed 's%/%\\/%g')
sed "s/$escaped/,\$s/foo/bar/" file

Netlik sağlamak için, $variabledizeyi içeriyorsa 1/2, yukarıdaki komutlar şuna eşdeğer olacaktır:

sed '\%1/2%,$s/foo/bar/' file

ilk durumda ve

sed '/1\/2/,$s/foo/bar/' file

saniyede.


4

Değişkenlerin birinci sınıf vatandaş olduğu, yalnızca genişleyen makroların olmadığı Perl'i kullanın:

var=/Users/Documents/name/file perl -pe 's/\Q$ENV{var}/replace/g' $file
  • -p girdi satırını satır satır okur ve işlendikten sonra satırı yazdırır
  • \QAşağıdaki dizedeki tüm meta karakterleri tırnak içine alır (burada sunulan değer için gerekli değildir, ancak değer içeriyorsa [veya diğer bazı değerler normal ifadeler için özelse gereklidir)

Stack Exchange'de düzinelerce "sed ifadesinde değişken kullanma" sorusuna genel olarak yararlı tek cevap. Diğer her şey, değişkenlerin ve sed'in değişkenliği göz önüne alındığında pratik olarak yararsız olan "sed'e özel her şeyden etkili bir şekilde kaçmaktır".
Heath Raftery
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.