Komutları kullanarak dosya içindeki metni bulma ve değiştirme


Yanıtlar:


1053
sed -i 's/original/new/g' file.txt

Açıklama:

  • sed = Akış Düzenleyici
  • -i = yerinde (yani orijinal dosyaya geri kaydet)
  • Komut dizesi:

    • s = substitute komutu
    • original = değiştirilecek kelimeyi tanımlayan normal bir ifade (veya sadece kelimenin kendisi)
    • new = ile değiştirilecek metin
    • g = global (yani hepsini değiştir ve yalnızca ilk oluşumu değil)
  • file.txt = dosya adı


3
@Akiva Eğer regex özel karakterler eklerseniz aramanıza uygun karakterlerlesed eşleşir. -rBunun yerine genişletilmiş RE'ler kullanmak istiyorsanız bir bayrak ekleyin .
Cscarney

32
@mcExchange Özellikle /eşleştirmeniz gereken karakterse, ayırıcı olarak başka bir karakter kullanabilirsiniz (örn. 's_old/text_new/text_g'). Aksi takdirde, kelimenin tam anlamıyla bir karakter elde etmek için \ herhangi birinden önce koyabilirsiniz $ * . [ \ ^.
Cscarney,

3
@BrianZ Dosya sistemi söz konusu olduğunda, sed'nin çıktısı aynı ada sahip yeni bir dosyadır. Bu böcek olmayan sık bildirilen hatalardan
cscarney 21:15

16
OSX komutu sed -i '.bak' 's/original/new/g' file.txtayrıca sıfır uzunluklu bir uzantıyla çalıştırılabilir sed -i '' 's/original/new/g' file.txt, bu da yedekleme yapmaz.
Kirk

19
MacOS kullanıcılarının -i '-' sonra -i ed.gs/2016/01/26/os-x-sed-invalid-command-code parametresi olarak '' " eklemeleri gerekecek, böylece dosyanın üzerine yazılacak.
geoyws

32

Bunu yapmanın birkaç farklı yolu vardır. Biri sedve Regex kullanıyor . SED, metni filtrelemek ve dönüştürmek için bir Akış Düzenleyicisidir. Bir örnek aşağıdaki gibidir:

marco@imacs-suck: ~$ echo "The slow brown unicorn jumped over the hyper sleeping dog" > orly
marco@imacs-suck: ~$ sed s/slow/quick/ < orly > yarly
marco@imacs-suck: ~$ cat yarly
The quick brown unicorn jumped over the hyper sleeping dog

Daha mantıklı olabilir başka bir yolu da < strinve > stroutborularla olduğunu!

marco@imacs-suck: ~$ cat yarly | sed s/unicorn/fox/ | sed s/hyper/lazy/ > nowai
marco@imacs-suck: ~$ cat nowai 
The quick brown fox jumped over the lazy sleeping dog

6
Not catiçinde cat file | sed '...'gereksizdir. Doğrudan söyleyebilirsiniz sed '...' file.
fedorqui

1
Nitekim bu daha da azaltılabilir: sed -i'.bak' -e 's/unicorn/fox/g;s/hyper/brown/g' yarlyeğe dosyası alacak ve bir yedekleme yaparken yerinde 2 değişiklik yapacaktır. time bash -c "$COMMAND"Zamanın kullanılması , bu sürümün ~ 5 kat daha hızlı olduğunu gösteriyor.
pbhj

23

Bunu başarmanın çok yolu var. Dize değiştirme ile neyin başarmaya çalıştığının karmaşıklığına bağlı olarak ve kullanıcının tanıdığı araçlara bağlı olarak, bazı yöntemler diğerlerinden daha fazla tercih edilebilir.

Bu cevapta input.txtburada verilen tüm örnekleri test etmek için kullanabileceğiniz basit bir dosya kullanıyorum . Dosya içeriği:

roses are red , violets are blue
This is an input.txt and this doesn't rhyme

BASH

Bash aslında metin işleme amaçlı değildir, ancak parametre genişletme yoluyla basit değişimler yapılabilir , özellikle burada basit yapıyı kullanabiliriz ${parameter/old_string/new_string}.

#!/bin/bash
while IFS= read -r line
do
    case "$line" in
       *blue*) printf "%s\n" "${line/blue/azure}" ;;
       *) printf "%s\n" "$line" ;;
    esac
done < input.txt

Bu küçük komut dosyası yerinde değiştirme işlemi yapmaz; bu, yeni metni yeni dosyaya kaydetmeniz ve eski dosyadan kurtulmanız gerektiği anlamına gelir; mv new.txt old.txt

Yan not: neden while IFS= read -r ; do ... done < input.txtkullanıldığını merak ediyorsanız , bu temel olarak kabuğun satır satır dosya okuma biçimidir. Bkz bu başvuru için.

AWK

Bir metin işleme aracı olan AWK, bu görev için oldukça uygundur. Düzenli ifadelere dayalı basit değiştirmeler ve çok daha gelişmiş olanları yapabilir . İki işlev sunar: sub()ve gsub(). Birincisi, sadece ilk oluşumun yerini alır, ikincisi ise tüm dizedeki oluşumları değiştirir. Örneğin, eğer dizgemiz varsa one potato two potato, sonuç şu olacaktır:

$ echo "one potato two potato" | awk '{gsub(/potato/,"banana")}1'
one banana two banana

$ echo "one potato two potato" | awk '{sub(/potato/,"banana")}1'                                      
one banana two potato 

AWK bir girdi dosyasını argüman olarak alabilir, bu yüzden aynı şeyleri yapmak input.txtkolay olacaktır:

awk '{sub(/blue/,"azure")}1' input.txt

Sahip olduğunuz AWK sürümüne bağlı olarak, yerinde düzenleme olabilir veya olmayabilir, bu nedenle olağan uygulama yeni metni kaydeder ve değiştirir. Örneğin böyle bir şey:

awk '{sub(/blue/,"azure")}1' input.txt > temp.txt && mv temp.txt input.txt

SED

Sed bir çizgi editörüdür. Ayrıca düzenli ifadeler kullanır, ancak basit değişiklikler için yapmanız yeterlidir:

sed 's/blue/azure/' input.txt

Bu araç için iyi olan şey, -ibayrakla etkinleştirebileceğiniz yerinde düzenlemeye sahip olmasıdır .

Perl

Perl, genellikle metin işlemede kullanılan başka bir araçtır, ancak genel amaçlı bir dildir ve ağ oluşturma, sistem yönetimi, masaüstü uygulamaları ve diğer birçok yerde kullanılır. C, sed, awk ve diğerleri gibi diğer dillerden birçok kavram / özellik ödünç aldı. Basit değiştirme işlemi şu şekilde yapılabilir:

perl -pe 's/blue/azure/' input.txt

Sed gibi perl de -i bayrağına sahiptir.

piton

Bu dil çok yönlüdür ve çok çeşitli uygulamalarda da kullanılır. Dizelerle çalışmak için birçok işlevi vardır replace(), ki bunlar arasında , eğer böyle bir değişkeniniz varsa var="Hello World",var.replace("Hello","Good Morning")

Dosyayı okumak ve içindeki dizeyi değiştirmek için basit bir yol böyle olurdu:

python -c "import sys;lines=sys.stdin.read();print lines.replace('blue','azure')" < input.txt

Ancak Python ile, ayrıca betiğin içinden de yapabileceğiniz yeni bir dosyaya çıkmanız gerekir. Örneğin, işte basit bir tane:

#!/usr/bin/env python
import sys
import os
import tempfile

tmp=tempfile.mkstemp()

with open(sys.argv[1]) as fd1, open(tmp[1],'w') as fd2:
    for line in fd1:
        line = line.replace('blue','azure')
        fd2.write(line)

os.rename(tmp[1],sys.argv[1])

Bu komut dosyası input.txtkomut satırı argümanı olarak çağrılmalıdır . Python betiğini komut satırı argümanıyla çalıştırmanın tam komutu şöyle olacaktır:

 $ ./myscript.py input.txt

veya

$ python ./myscript.py input.txt

Tabii ki, ./myscript.pygeçerli çalışma dizininizde olduğundan ve ilk olarak çalıştırılabilir olarak ayarlandığından emin olun.chmod +x ./myscript.py

Python ayrıca düzenli ifadelere sahip olabilir, özellikle, daha gelişmiş değişimler için kullanılabilecek fonksiyona resahip bir modül var re.sub().


1
Güzel derleme! Burada bahsedilmeyen bir başka olası yol da trkomutu unix olarak kullanmaktır
Tapajit Dey

1
@TapajitDey Evet, tr başka harika bir araç, ancak örneğin (karakter setleri değiştirilmesi için olduğuna dikkat tr abc cdeçevirmek olacaktır aiçin c, bhiç dbu gibi tam kelimeleri değiştirerek biraz farklıdır. sedYapython
Sergiy Kolodyazhnyy

22

Vim'i Ex modunda kullanabilirsiniz:

ex -s -c '%s/OLD/NEW/g|x' file
  1. % tüm satırları seç

  2. s vekil

  3. g her satırdaki tüm örnekleri değiştirin

  4. x Değişiklik yapılmışsa yaz (varsa)


21

Awk’nin gsub komutuyla

awk '{gsub(/pattern/,"replacement")}' file

Örnek:

awk '{gsub(/1/,"0");}' file

Yukarıdaki örnekte, tüm 1'ler, bulunduğu sütuna bakılmaksızın 0 ile değiştirilir.


Belirli bir sütunda değişiklik yapmak istiyorsanız, böyle yapın,

awk '{gsub(/pattern/,"replacement",column_number)}' file

Örnek:

awk '{gsub(/1/,"0",$1);}' file

Yalnızca ilk sütunda 1 ile 0 olur.

Perl’den

$ echo 'foo' | perl -pe 's/foo/bar/g'
bar

Bunu MacOS terminalinde kullandım ve hiçbir şey yapmadı ...
Jim

Alpine Linux'ta (Docker konteynerinde) test edildi ve çıktı
almadı

@ SalathielGenèse ne yapmaya çalışıyorsun?
Avinash Raj

Dosyayı env inotifywaitaltında izliyorum shve verileri CSV biçiminde rapor ediyorum (çünkü özel biçim buggy). Sonra CSV belgesini kabuk betiklerinde kullanmanın basit bir yolu olmadığını düşündüm ... Ve çok hafif istiyorum. Bu yüzden CSV'yi ayrıştırmak ve raporlamak için oldukça basit bir senaryo başlattım. CSV spesifikasyonunu okudum ve beklediğimden daha ayrıntılı olduğunu ve çift tırnak içine alınmış çoklu satır değerini desteklediğini fark ettim. sedTokenleştirmeye güveniyordum ama kısa sürede sedmultiline dediğimiz şeyin iki hatta kadar olduğunu fark ettim . Peki ya CSV değerlerinden biri ikiden fazla satıra yayılıyorsa?
Salathiel Genèse

sorununuzu soru olarak sormak daha iyi.
Avinash Raj

8

sedolduğunu s Team, ed in- kullanabileceğiniz ki |göndermeye (boru) standart akışları aracılığıyla (Standart giriş ve çıkışı özellikle) sedve Unix felsefesi geleneğinde bir araçtır yapım anında programlı bunları değiştirmek; ancak, -iaşağıda belirtilen parametreyi kullanarak da dosyaları doğrudan düzenleyebilir .
Aşağıdakileri göz önünde bulundurun :

sed -i -e 's/few/asd/g' hello.txt

s/için kullanılır s Bulunan ifade yerini tutmaz fewile asd:

Birkaç, cesur.


Asd, cesur.

/g"Global" anlamına gelir, bunu bütün çizgi için yapmak anlamına gelir. Bırakırsanız /g(ile s/few/asd/ne olursa olsun her zaman üç eğik çizgi olması gerekir) ve fewaynı satırda iki kez görünürse, yalnızca ilki fewolarak değiştirilir asd:

Birkaç erkek, birkaç kadın, cesur.


Asd adamları, az sayıda kadın, cesur.

Bu, bazı durumlarda, satırların başlangıcında özel karakterlerin değiştirilmesi gibi (örneğin, bazı kişilerin e-posta dizilerinde önceki materyali alıntı yapmak için kullandıklarından daha büyük sembollerin yerine, satırın ilerisinde alıntı yapılan bir cebirsel eşitsizlik bırakarak, yatay bir sekmeyle değiştirmek gibi) yararlıdır. dokunulmamış), ancak örneğinizde herhangi bir yerde few meydana geldiğini belirttiğiniz yerde değiştirilmeli, bunun olduğundan emin olun /g.

Aşağıdaki iki seçenek (bayraklar) bire birleştirilmiştir -ie:

-iseçenek düzenlemek için kullanılır ı n dosyada yer hello.txt.

-eseçenek bu durumda, çalışacak e xpression / komutunu gösterir s/.

Not: -i -eAramak / değiştirmek için kullanmanız önemlidir . Bunu yaparsanız -ie, 'e' harfi eklenmiş her dosyanın bir yedeğini yaratırsınız.


2

Böyle yapabilirsin:

locate <part of filaname to locate> | xargs sed -i -e "s/<Old text>/<new text>/g" 

Örnekler: [logdir ',' '] ([] olmadan) tüm oluşumları, locate komutunun sonucu olan tüm dosyalarda [logdir', os.getcwd ()] ile değiştirmek için, şunları yapın:

ex1:

locate tensorboard/program.py | xargs sed -i -e "s/old_text/NewText/g"

ex2:

locate tensorboard/program.py | xargs sed -i -e "s/logdir', ''/logdir', os.getcwd()/g"

[tensorboard / program.py] aranacak dosyada


Selam. Seçtiğiniz karakter dizileri ( logdir', ''-> /logdir', os.getcwd()) bu cevabı ayrıştırmayı zorlaştırır. Ayrıca, cevabınızın öncelikle sed'in kullanılacağı dosyaları bulacağını belirtmeye değer, çünkü bu sorunun bir parçası değil.
mwfearnley

Merhaba, bu cevap hem arama hem de dosyada <eski metin> bulunursa hepsini değiştirdi.
Nguyấn Tuấn Anh

Trasorboard kullandıklarını keraslarda kullandıkları için bu cevabı seçtim, komutunu değiştirmek isteyen: tensorboard --logdir = '/ path / to / log / klasör /': tensorboard sadece loglar klasöründe kalırken. çok uygun
Nguyễn Tuấn Anh 24:18
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.