Sed'de çoklu yeniden kullanım için karmaşık bir normal ifadeyi nasıl kaydedersiniz?


12

Kullanırken sed, genellikle bir dosyada iki kez eşleşmem gereken oldukça karmaşık ve karmaşık regex'ler oluştururum. Bu normal ifadeyi kaydetmenin ve sadece iki kez referans almamın bir yolu var mı?

Belki de buna benzeyen bir şey?

sed ' complicated_regex=/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+$/
s/complicated_regex:complicated_regex/simple-output/
' my_file

Güncelleme: Bir cevap bash değişkeni kullanma çözümünü sundu. Bu işe yaramıyor. Verilen a test.txt.

#test.txt
foo bar
bar foo

Ve senaryo

#!/bin/bash

VALUE='foo \([a-z]\+\)'

sed 's/"${VALUE}"/foo happy \1/' test.txt

Bu çıktıyı üretmelidir

foo happy bar
bar foo

Ama bunun yerine hatayı alıyorum

sed: -e expression #1, char 24: invalid reference \1 on `s' command's RHS

Perl kullanırsanız, ifadenin içindeki ifadenin önceki bölümlerine başvurabilirsiniz:perl -pe 's/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+:\1$/simple_output/' my_file
glenn jackman

1
Sed için çok karmaşık bir şey bulduğunuzda, awk veya perl için tereddüt etmeyin.
Gilles 'SO- kötü olmayı bırak'

2
@Cory: Sözdizimini doğru yaparsanız örneğin iyi çalışır. Hala beklediğiniz kabuk genişlemesinden gizleyen 'tek tırnak' içine alınmış "$ değişkeni" var ... olması gerekirsed 's/'"${VALUE}"'/foo happy \1/' test.txt
Peter.O 4

Yanıtlar:


7

Kabuk değişkenlerini kullanabilirsiniz:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+'
sed s/^"$complicated_regex":"$complicated_regex"\$/'simple-output'/ my_file

Ne demek istediğinden emin değilim $i, ama tek tırnakların dışına koyman gerekebilir:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{'"$i"'}})?)+'

Tabii ki bu sadece sedkomut kabuktan çağrıldığında çalışır , ancak neredeyse tüm programlama dillerinde benzer bir çözüm vardır. (Ve içinde değişkenler kullanmanın mümkün olduğunu düşünmüyorum sed.)
Stéphane Gimenez

Hrm. Bunu denemek, geri başvurular bozuk gibi görünüyor. s/$complicated_regex/\1/geçersiz bir başvuru olduğunu belirten bir hata veriyor.
Cory Klein

Ah, belki benim hatam, değişken ikameleri zsh yapmaya alışkınım. Güncellenmiş cevaba bakınız.
Stéphane Gimenez

Değişken çapa kaldırmak ve sed komut dosyasında koymak zorunda kalacak:sed "s/^${complicated_regex}:${complicated_regex}\$/simple-output/" my_file
glenn jackman

Duh! Evet, geçerli bir normal ifade birleştirme sağlandığını kontrol etmeyi unuttum :-)
Stéphane Gimenez

0

Bir kabuk değişkeni değerine düşmenin sedve ters eğik çizgiden kaçmanın sedkomut dosyanızın geri kalanı için nasıl değişmesi gerektiği konusunda endişelenmemenin en kolay yolu , değişken hariç her şeyi tek tırnak içine almak ve bunu çift tırnak içine almaktır.

Aşağıdaki kod örneklerinin tümü varsayılmaktadır: VALUE='foo \([a-z]\+\)'

Değişken genişletilmediğinden aşağıdaki bozuk kod başarısız oluyor VALUE:

sed 's/"${VALUE}"/foo happy \1/' test.txt

Aşağıdaki kırık üzerinde ters eğik çizgi çünkü kod başarısız \1(çift tırnak yerine tek tırnak içinde çünkü) kabuk tarafından yemiş olur önce sedhiç görüyor:

sed "s/${VALUE}/foo happy \1/" test.txt

Aşağıdaki kod beklendiği gibi çalışır:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt

Tho aşağıdaki kod da çalışır:

sed "s/${VALUE}/foo happy \\1/" test.txt

Aşağıdakiler de öyle:

sed s/"${VALUE}"/foo\ happy\ \\1/ test.txt

Ama neden karmaşık hale geliyor? Bir sedbetiğin etrafındaki tek tırnaklar , özellikle kodunuzu okuyan kabuk-betik-olmayan gurular için her şeyi daha açık hale getirir. Benim tercih ettiğim yol, yine, sadece değişken genişleme için tek tırnaklardan çift tırnaklara bırakmak ve doğrudan tek tırnaklara atlamak:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt
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.