Metin dosyasında değiştirme ** ** normal ifade olmadan


68

Bir metin dosyasının içindeki bazı metinlerin yerine yenisini kullanmam gerekiyor. Genellikle böyle bir şey yapardım

sed -i 's/text/replacement/g' path/to/the/file

Sorun hem olmasıdır textve replacementböylece tire, eğik çizgi, blackslashes, tırnak ve içeren karmaşık dizelerdir. Eğer içindeki tüm gerekli karakterlerden kaçarsam text, o şey hızlıca okunamaz hale gelir. Öte yandan, düzenli ifadelerin gücüne ihtiyacım yok: Sadece metni tam anlamıyla değiştirmem gerekiyor.

Metin değişikliğini yapmak için bir yolu var mı olmadan bazı kabuk komutuyla normal ifadeler kullanarak?

Bunu yapan bir senaryo yazmak oldukça önemsiz olurdu, ama zaten orada bir şeyler olması gerektiğini düşündüm.


Bash yapmak için gerekli? Basit bir çözüm, Word'de açmak ve yapmak olacaktırfind and replace all
Akash

17
@akash Çünkü bashher zaman Microsoft Word ile birlikte gelen sistemler ? ;) Hayır sadece şaka. OP, uzak bir makinede veya bir grup dosya için bunu yapmak isteyebilir.
slhck

@slhck :) Eh, sanırım gedit benzer bir seçeneğe sahip olmalıdır
Akash

Bir seçenek olacaktır nasılsa doğru geçirmeden önce her şeyi kaçmak sedmuhtemelen tüm anahtarları ve platform farklılıkları dikkate beyhude bir çaba olan.
l0b0

Yanıtlar:


6

Normal ifadelerin gücüne ihtiyaç duymadığınızda, kullanmayın. Bu iyi.
Ancak, bu gerçekten normal bir ifade değil .

sed 's|literal_pattern|replacement_string|g'

Öyleyse, eğer /senin probleminse kullan |ve eskiden kaçmana gerek yok.

ps: yorumlar hakkında, ayrıca , sed arama kalıbı için bir dizgeden kaçış hakkında bu Stackoverflow cevabına bakın .


Güncelleme: ince kullanıyorsanız Perl ile deneyin \Qve \Ebu gibi
perl -pe 's|\Qliteral_pattern\E|replacement_string|g'
RedGrittyBrickburada da bir açıklama daha güçlü Perl sözdizimi ile benzer bir hile önerdi


Teşekkürler, / ve | arasındaki farkları bilmiyordum.
Andrea

64
Bu yanıtın yararlı olduğundan emin değilim ... arasındaki tek fark s|||ve s///ayırıcı karakteri o kadar farklı ve olmasıdır tek karakter çıkış yapılmasını gerektirmez. Eşit olarak yapabilirsin s###. Buradaki asıl mesele, OP'nin literal_pattern(gerçek anlamıyla olmayan ve regex olarak yorumlanacak) içeriğinden kaçmak konusunda endişelenmek istememesidir .
Benj

15
Bu, diğer özel karakterlerin yorumlanmasından kaçınmaz. Peki ya 1234.*aaaçözümünüzü araştırırsanız , amaçlanandan çok daha fazlasını eşleştirir 1234\.\*aaa.
Matteo,

20
Bu cevap kabul edilmemelidir
Steven Lu

2
Bu tamamen konuyu özlüyor. Eşleştirilecek metin herhangi bir gariplik içerebilir. Benim durumumda bu rasgele bir şifre. Bunların nasıl gittiğini biliyorsunuz
Christian Bongiorno

13
export FIND='find this'
export REPLACE='replace with this'
ruby -p -i -e "gsub(ENV['FIND'], ENV['REPLACE'])" path/to/file

Buradaki tek% 100 güvenli çözüm, çünkü:

  • Statik bir alt yapıdır, düzenli değil, herhangi bir şeyden kaçmaya gerek yoktur (bu nedenle kullanmaktan üstündür sed)
  • Dize karakter içeriyorsa kırılmaz }(bu nedenle gönderilen bir Perl çözümünden üstündür)
  • Hiçbir karakterden kopmaz, çünkü ENV['FIND']kullanılır, kullanılmaz $FIND. İle $FINDveya metin Yakut kodunda inlined dize bir çıkmamış içeriyorsa, bir sözdizimi hatası vurabilir '.

Ben kullanmak zorunda export FIND='find this; export REPLACE='replace with this';böylece benim bash komut ENV['FIND']ve ENV['replace']beklenen değerleri vardı. Bir dosyadaki gerçekten uzun şifreli dizeleri değiştiriyordum. Bu sadece biletti.
DMfll

Bu iyi bir cevap cevap çünkü güvenilir ve yakut her yerde. Bu cevaba göre şimdi bu kabuk betiğini kullanıyorum .
loevborg

FIND birden fazla satır içerdiğinde maalesef çalışmıyor.
adrelanos,

FIND'da çoklu çizgilerle çalışmasını engelleyecek hiçbir şey yoktur. Çift alıntı \ n kullanın.
Nowaker

7

replaceKomut yapacağız.

https://linux.die.net/man/1/replace

Yerinde değişiklik:

replace text replacement -- path/to/the/file

Stdout’a:

replace text replacement < path/to/the/file

Örnek:

$ replace '.*' '[^a-z ]{1,3}' <<EOF
> r1: /.*/g
> r2: /.*/gi
> EOF
r1: /[^a-z ]{1,3}/g
r2: /[^a-z ]{1,3}/gi

replaceKomut MySQL veya mariadb ile birlikte gelir.


3
hesaba katılması yerine geçerliliğini yitirmiş ve gelecekte kabul edilemez olabilir
Rogelio

1
Neden dünyada böyle bir temel komut bir veritabanı ile geliyor?
masterxilo

3
@masterxilo Daha iyi bir soru olabilir - neden bu kadar basit bir komut modern işletim sistemleriyle gelmiyor? ;-)
Mark Thomson,


3

Perl betiğimi kontrol et. Düzenli ifadenin örtülü veya açık kullanımı olmadan tam olarak ihtiyacınız olanı yapar:

https://github.com/Samer-Al-iraqi/Linux-str_replace

str_replace Search Replace File # replace in File in place

STDIN | str_replace Search Replace # to STDOUT

çok kullanışlı değil mi? Bunu yapmak için Perl'i öğrenmek zorunda kaldım. çünkü gerçekten buna ihtiyacım var.


2

Desenlerinizi kaçarak bunu yapabilirsiniz . Bunun gibi, böyle:

keyword_raw='1/2/3'
keyword_regexp="$(printf '%s' "$keyword_raw" | sed -e 's/[]\/$*.^|[]/\\&/g')"
# keyword_regexp is now '1\/2\/3'

replacement_raw='2/3/4'
replacement_regexp="$(printf '%s' "$replacement_raw" | sed -e 's/[\/&]/\\&/g')"
# replacement_regexp is now '2\/3\/4'

echo 'a/b/c/1/2/3/d/e/f' | sed -e "s/$keyword_regexp/$replacement_regexp/"
# the last command will print 'a/b/c/2/3/4/d/e/f'

Bu çözümler için krediler buraya geliyor: https://stackoverflow.com/questions/407523/escape-a-string-for-a-sed-replace-pattern

Not1: Bu sadece boş olmayan anahtar kelimeler için işe yarar. Boş anahtar kelimeler sed ( sed -e 's//replacement/') tarafından kabul edilmez .

Not2: Maalesef, sorunu çözmek için regexp-s kullanmayacak popüler bir araç bilmiyorum. Böyle bir aracı Pas veya C ile yazabilirsiniz, ancak varsayılan olarak yoktur.


Bu tamamen OP'nin amacını özlüyor. Belli ki, kalıptan kaçabilirsiniz, ancak bazı kalıplar için bu can sıkıcıdır.
icecreamsword

@icecreamsword, ilk satırın altındaki cevabımı okudunuz mu? Komut otomatik olarak kaçıyor .
VasyaNovikov

1

Birkaç cevap daha ekledim ve bununla karşılaştım:

function unregex {
   # This is a function because dealing with quotes is a pain.
   # http://stackoverflow.com/a/2705678/120999
   sed -e 's/[]\/()$*.^|[]/\\&/g' <<< "$1"
}
function fsed {
   local find=$(unregex "$1")
   local replace=$(unregex "$2")
   shift 2
   # sed -i is only supported in GNU sed.
   #sed -i "s/$find/$replace/g" "$@"
   perl -p -i -e "s/$find/$replace/g" "$@"
}

Newlines ile çalışmıyor. Ayrıca yeni hatlardan kaçmaya yardımcı olmuyor \n. Herhangi bir çözüm?
adrelanos

1

PHP'nin str_replace kullanabilirsiniz :

php -R 'echo str_replace("\|!£$%&/()=?^\"'\''","replace",$argn),PHP_EOL;'<input.txt >output.txt

Not: Yine de, tek tırnaklardan 've çift tırnaktan kaçmanız gerekir ".


0

Düğüm.JS @Nowaker eşdeğeri:

export FNAME='moo.txt'
export FIND='search'
export REPLACE='rpl'
node -e 'fs=require("fs");fs.readFile(process.env.FNAME,"utf8",(err,data)=>{if(err!=null)throw err;fs.writeFile(process.env.FNAME,data.replace(process.env.FIND,process.env.REPLACE),"utf8",e=>{if(e!=null)throw e;});});'

0

Heres bir daha "neredeyse" çalışma yolu.

Vi veya vim kullanın.

İçinde yerine geçeceğiniz bir metin dosyası oluşturun:

:% sno / arama dizgem \ \ "-: # 2; g ('. j'); \\"> / yer değiştirim = \\ "bac) (o: # 46; \\"> /
: x

daha sonra komut satırından vi veya vim'i çalıştırın:

vi -S commandfile.txt path/to/the/file

:% sno sihir olmadan arama yapmak ve değiştirmek için vi komutudur.

Benim seçili ayırıcım.

: x kaydeder ve çıkar vi.

'\' Ters eğik çizgiden kaçmanız gerekiyor. '' ' veya aramanızda bulunmayan başka bir şey ya da string-string, pipe '|' benim için işe yaramadı tho.

ref: https://stackoverflow.com/questions/6254820/perform-a-non-regex-search-replace-in-vim https://vim.fandom.com/wiki/Search_without_need_to_escape_slash http://linuxcommand.org/ lc3_man_pages / vim1.html

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.