Yanıtlar:
cd /path/to/your/folder
sed -i 's/foo/bar/g' *
"Foo" oluşumu "bar" ile değiştirilir.
MacOS gibi BSD sistemlerinde, sayfa -i '.bak'
başına "risk bozulması veya kısmi içerik" gibi bir yedekleme uzantısı sağlamanız gerekir .
cd /path/to/your/folder
sed -i '.bak' 's/foo/bar/g' *
sed
, -i
eski dosya adlarını eklenir peşinden bir dize gerektirir. Böylece sed -i .bak 's/foo/bar/g' *.xx
tüm .xx
dosyaları eşdeğer .xx.bak
isme taşır ve ardından .xx
foo → bar değiştirmeli dosyaları oluşturur .
sed -i 's/foo\ with\ spaces/bar/g' *
. Sanırım çok uzun zaman sonra öğrendiniz ... ama bu şekilde başkaları da aynı sorunu buluyor.
sed -i -e 's/foo/bar/g' $(find /home/user/base/dir)
Kaspar'ın cevabına benzer, ancak bir satırdaki tüm olayları değiştirmek için g bayrağıyla.
find ./ -type f -exec sed -i 's/string1/string2/g' {} \;
Global büyük / küçük harfe duyarlı olmayanlar için:
find ./ -type f -exec sed -i 's/string1/string2/gI' {} \;
LC_ALL=C find ./ -type f -exec sed -i '' -e 's/proc.priv/priv/g' {} \;
( bu gönderiye ve buna bakın )
--include=*.whatever
-r
.git/
. Daha cd
düşük bir seviyeye inin.
git status
döndürür: error: bad index file sha1 signature.... fatal: index file corrupt
. Ne oluyor?
@ kev'in cevabı iyidir, ancak yalnızca hemen dizindeki dosyaları etkiler.Aşağıdaki örnekte, dosyaları yinelemeli olarak bulmak için grep kullanılır. Her zaman benim için çalışıyor.
grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @
Komut dökümü
grep -r : --recursive , her dizinin altındaki tüm dosyaları tekrar tekrar oku.
grep -l : - eşleşmeli baskı, eşleşen satırları yazdırmak yerine eşleşmesi olan her dosyanın adını yazdırır.
grep -i : --ignore-case .
xargs : STDIN'i argümanlara dönüştürün, bu cevabı takip edin .
Xargs -i @ ~ komutu içerir @ ~ : bağımsız değişkeni için bir tutucu olarak belirli bir konumda kullanılacak ~ komutu ~ , 'işareti herhangi bir dize ile ikame olabilecek bir tutucudur.
-i sed , yerinde düzenleme dosyaları: olmadan yedeklemeler.
sed s / regexp / replacement / : regexp yerine yedek dize yazın .
sed s / regexp / replacement / g : global olarak , sadece ilk maç yerine her maçın yedeğini alın.
grep --include={*.php,*.html,*.js} -rnl './' -e "old-word" | xargs -i@ sed -i 's/old-word/new-word/g' @
|
, ayrıca, neden -i
xargs komutunda? Kullanım kılavuzunda kullanımdan kaldırıldığını ve -I
bunun yerine kullanılması gerektiğini okudum . Ve @
desen için başlangıç ve bitiş için bir sınırlayıcı olarak kullanılır?
grep -rli 'old-word' * | xargs -I@ sed -i '' 's/2.0.0/latest/g' @
rli
) ve @
örneğin işaretini
Bu benim için çalıştı:
find ./ -type f -exec sed -i 's/string1/string2/' {} \;
Howerver, bu vermedi: sed -i 's/string1/string2/g' *
. Belki "foo", string1 ve "bar" string2 değil.
find ./ -type f -exec sed -i '' -e 's/string1/string2/' {} \;
Zaten listelenen bu sorunun birkaç standart cevabı vardır. Genellikle, dosyaları özyinelemeli olarak listelemek ve sonra sed veya perl ile işlemleri yapmak için find komutunu kullanabilirsiniz .
Çoğu hızlı kullanım için, rpl komutunun hatırlanması çok daha kolay olabilir. İşte tüm dosyalarda özyinelemeli değiştirme (foo -> bar):
rpl -R foo bar .
Muhtemelen yüklemeniz gerekir ( apt-get install rpl
veya benzeri).
Bununla birlikte, düzenli ifadeler ve geri değiştirme veya dosya adlarının yanı sıra arama ve değiştirme içeren daha zorlu işler için, farkında olduğum en genel ve güçlü araç repren , bazıları için bir süre geri yazdığım küçük bir Python betiği diken yeniden adlandırma ve yeniden düzenleme görevleri. Tercih etmenizin nedenleri:
Kullanmak için pip install repren
. Örnekler için README'ye bakın.
Birden çok dosyadaki bir dizeyi değiştirmek için şunları kullanabilirsiniz:
grep -rl string1 somedir/ | xargs sed -i 's/string1/string2/g'
Örneğin
grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'
Dosyalar içindeki bir yolu değiştirmek için (kaçış karakterlerinden kaçınmak) aşağıdaki komutu kullanabilirsiniz:
sed -i 's@old_path@new_path@g'
@ İşareti, tüm özel karakterlerin aşağıdaki dizede yok sayılması gerektiği anlamına gelir.
Dizenizde eğik çizgi (/) varsa, sınırlayıcıyı '+' olarak değiştirebilirsiniz.
find . -type f -exec sed -i 's+http://example.com+https://example.com+g' {} +
Bu komut geçerli dizinde yinelemeli olarak çalışır.
../domain.com
içindomain.com
"Foo" nun ilk satır tekrarları "bar" ile değiştirilir. Ve kontrol etmek için ikinci satırı kullanabilirsiniz.
grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
grep 'foo' -r * | awk -F: {'print $1'} | sort -n | uniq -c
grep -rl 'foo' . | xargs sed -i 's/foo/bar/g'
Kullanabileceğiniz dosya listeniz varsa
replace "old_string" "new_string" -- file_name1 file_name2 file_name3
Tüm dosyalarınız varsa kullanabilirsiniz
replace "old_string" "new_string" -- *
Uzantısı olan dosya listeniz varsa şunu kullanabilirsiniz:
replace "old_string" "new_string" -- *.extension
replace "old_string" "new_string" -- *.txt
replace
yardımcı programı nereden alacağınızı eklemek daha iyidir . Bu bilgi olmadan, bu cevap eksiktir.
Dizeyi aramak search
ve onu replace
birden çok dosyayla değiştirmek istediğiniz göz önüne alındığında , bu benim savaş testli, tek satırlık formülüm :
grep -RiIl 'search' | xargs sed -i 's/search/replace/g'
Hızlı grep açıklaması:
-R
- özyinelemeli arama-i
- büyük / küçük harfe duyarlı değil-I
- ikili dosyaları atla (metin istiyorsun, değil mi?)-l
- çıktı olarak basit bir liste yazdırın. Diğer komutlar için gerekliDaha sonra grep çıktısı, metnin yerini almak için kullanılan sed'e (xargs aracılığıyla) geçirilir. -i
Bayrak dosyayı doğrudan değiştirecektir. Bir çeşit "kuru çalışma" modu için çıkarın.
"Bul ve sed'i de kullanabilirsiniz, ancak bu küçük perl çizgisinin güzel çalıştığını görüyorum.
perl -pi -w -e 's/search/replace/g;' *.php
"( Http://www.liamdelahunty.com/tips/linux_search_and_replace_multiple_files.php sayfasından alınmıştır )
En iyi sonuçlarım perl ve grep kullanmaktan geliyor (dosyanın arama ifadesine sahip olmasını sağlamak için)
perl -pi -w -e 's/search/replace/g;' $( grep -rl 'search' )
Bu soruyu (ve cevapları) bulmadan önce kendi çözümümü hazırladım. Ben "benim uygulama", çünkü "yerine" "birkaç" ve "xml" farklı kombinasyonları aradım, ama bu belirli bir bulamadık.
Benim sorunum: Test nesneleri için karmaşık nesneler içeren verilerle bahar xml dosyaları vardı. Java kaynak kodundaki bir refactor birçok sınıfı değiştirdi ve xml veri dosyalarına uygulanmadı. Test senaryoları verilerini kaydetmek için, çeşitli dizinlere dağıtılan tüm xml dosyalarındaki tüm sınıf adlarını değiştirmem gerekiyordu. Tüm orijinal xml dosyalarının yedek kopyalarını kaydederken (bu bir zorunluluk olmamasına rağmen, sürüm kontrolü beni burada kurtaracaktır).
find
+ ' Nın bir kombinasyonunu arıyordum sed
, çünkü başka durumlarda benim için çalıştı, ancak aynı anda birkaç değişiklikle değil.
Sonra ask ubuntu yanıt buldum ve benim komut satırı oluşturmak yardımcı oldu:
find -name "*.xml" -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;
Ve mükemmel çalıştı (iyi, benim durumumda altı farklı yedek vardı). Ancak, geçerli dizinin altındaki tüm * .xml dosyalarına dokunacağını lütfen unutmayın. Bu nedenle, ve bir sürüm kontrol sisteminden sorumlu iseniz, önce filtrelemek isteyebilirsiniz ve sadece sed
gerçekten istediğiniz dizelere sahip olanlara geçmek isteyebilirsiniz; sevmek:
find -name "*.xml" -exec grep -e "firstWord" -e "secondWord" -e "thirdWord" {} \; -exec sed -s --in-place=.bak -e 's/firstWord/newFirstWord/g;s/secondWord/newSecondWord/g;s/thirdWord/newThirdWord/g' {} \;
findstr /spin /c:"quéquieresbuscar" *.xml
Bu kullanışlı olacaktır.
Gerçekten topal, ama herhangi bir sed komutları OSX üzerinde çalışmak için alamadım, bu yüzden bunun yerine bu aptalca şey yaptım:
:%s/foo/bar/g
:wn
^ - bu üç satırı panoya kopyala (evet, bitiş satırını ekle), sonra:
vi *
ve hiçbir dosya kalmadığını söyleyene kadar command-v tuşunu basılı tutun.
Salak ... hacky ... etkili ...
MacBook Pro'da aşağıdakileri kullandım ( https://stackoverflow.com/a/19457213/6169225'ten esinlenerek ):
sed -i '' -e 's/<STR_TO_REPLACE>/<REPLACEMENT_STR>/g' *
-i ''
hiçbir yedek almamanızı sağlar.
-e
modern normal ifade için.
-e
sadece sed'e bir sonraki tokenin bir komut olduğunu söyler. Genişletilmiş düzenli ifadeler için -E
kullanın.
Akış düzenleyicisi, -i
anahtarla çağrıldığında birden çok dosyayı “inplace” üzerinde değiştirir; bu, argüman olarak biten bir yedekleme dosyasını alır. Yani
sed -i.bak 's/foo/bar/g' *
bu klasördeki tüm dosyalarda foo
ile değiştirilir bar
, ancak alt klasörlere inmez. Ancak bu, .bak
dizininizdeki her dosya için yeni bir dosya oluşturur . Bunu, bu dizindeki tüm dosyalar ve tüm alt dizinleri için yinelemeli olarak yapmak için find
, dizin ağacında gezinmek için bir yardımcıya ihtiyacınız vardır .
find ./ -print0 | xargs -0 sed -i.bak 's/foo/bar/g' *
find
find ./ -name '*.php' -or -name '*.html' -print0
gerektiğinde başka argümanlar belirterek hangi dosyaların değiştirileceği konusunda daha fazla kısıtlama yapmanızı sağlar .
Not: GNU sed
bir dosya sonlandırması gerektirmez sed -i 's/foo/bar/g' *
, aynı zamanda çalışacaktır; FreeBSD sed
bir uzantı talep ediyor, ancak aralarında boşluk bırakıyor, bu yüzden sed -i .bak s/foo/bar/g *
çalışıyor.
multiedit komutu için komut dosyası
multiedit [-n PATTERN] OLDSTRING NEWSTRING
Kaspar'ın cevabından komut satırı argümanlarını kabul etmek ve isteğe bağlı olarak bir desenle eşleşen dosya adlarını sınırlamak için bir bash betiği yaptım. $ PATH içine kaydedin ve çalıştırılabilir yapın, sonra yukarıdaki komutu kullanın.
İşte senaryo:
#!/bin/bash
_help="\n
Replace OLDSTRING with NEWSTRING recursively starting from current directory\n
multiedit [-n PATTERN] OLDSTRING NEWSTRING\n
[-n PATTERN] option limits to filenames matching PATTERN\n
Note: backslash escape special characters\n
Note: enclose STRINGS with spaces in double quotes\n
Example to limit the edit to python files:\n
multiedit -n \*.py \"OLD STRING\" NEWSTRING\n"
# ensure correct number of arguments, otherwise display help...
if [ $# -lt 2 ] || [ $# -gt 4 ]; then echo -e $_help ; exit ; fi
if [ $1 == "-n" ]; then # if -n option is given:
# replace OLDSTRING with NEWSTRING recursively in files matching PATTERN
find ./ -type f -name "$2" -exec sed -i "s/$3/$4/g" {} \;
else
# replace OLDSTRING with NEWSTRING recursively in all files
find ./ -type f -exec sed -i "s/$1/$2/" {} \;
fi
Dosya ters eğik çizgi içeriyorsa (genellikle yollar) aşağıdaki gibi bir şey deneyebilirsiniz:
sed -i -- 's,<path1>,<path2>,g' *
örn:
sed -i -- 's,/foo/bar,/new/foo/bar,g' *.sh (in all shell scripts available)
Kişisel İngilizce düğümümü korumak için, bir dizinin altındaki tüm dosyalar için özyinelemeli olarak birden çok eski / yeni dizenin yerini almaya yardımcı olan bir yardımcı program komut dosyası yazdım.
Birden çok eski / yeni dize çifti karma haritada yönetilir.
Dizin komut satırı veya ortam değişkeni ile ayarlanabilir, harita kodda sabit olarak kodlanır, ancak gerekirse bir dosyadan yüklenecek kodu değiştirebilirsiniz.
Bazı yeni özelliklerden dolayı bash 4.2 gerektirir.
en_standardize.sh:
#! /bin/bash
# (need bash 4.2+,)
#
# Standardize phonetic symbol of English.
#
# format:
# en_standardize.sh [<dir>]
#
# params:
# * dir
# target dir, optional,
# if not specified then use environment variable "$node_dir_en",
# if both not provided, then will not execute,
# *
#
paramCount=$#
# figure target dir,
if [ $paramCount -ge 1 ]; then # dir specified
echo -e "dir specified (in command):\n\t$1\n"
targetDir=$1
elif [[ -v node_dir_en ]]; then # environable set,
echo -e "dir specified (in environment vairable):\n\t$node_dir_en\n"
targetDir=$node_dir_en
else # environable not set,
echo "dir not specified, won't execute"
exit
fi
# check whether dir exists,
if [ -d $targetDir ]; then
cd $targetDir
else
echo -e "invalid dir location:\n\t$targetDir\n"
exit
fi
# initial map,
declare -A itemMap
itemMap=( ["ɪ"]="i" ["ː"]=":" ["ɜ"]="ə" ["ɒ"]="ɔ" ["ʊ"]="u" ["ɛ"]="e")
# print item maps,
echo 'maps:'
for key in "${!itemMap[@]}"; do
echo -e "\t$key\t->\t${itemMap[$key]}"
done
echo -e '\n'
# do replace,
for key in "${!itemMap[@]}"; do
grep -rli "$key" * | xargs -i@ sed -i "s/$key/${itemMap[$key]}/g" @
done
echo -e "\nDone."
exit
Ack komutunu kullanmak şöyle hızlı olur:
ack '25 Essex' -l | xargs sed -i 's/The\ fox \jump/abc 321/g'
Ayrıca, arama sonucunda boşluk varsa. Kaçmak zorundasın.
Python kaynaklarında ortak bir hata hatası düzeltmek için bir örnek veriyorum.
Grep / sed yaklaşımını deneyebilirsiniz. İşte GNU sed ile çalışan ve git deposunu bozmayacak bir tanesi:
$ grep -rli --exclude '*.git*' '#!/usr/bin/python' . | xargs -I {} \
gsed -i '' -e 's/#!\/usr\/bin\/python/#!\/usr\/bin\/env python/' {}
Veya greptile kullanabilirsiniz :)
$ greptile -x .py -l -i -g '#!/usr/bin/env python' -r '#!/usr/bin/python' .
Sadece ilk senaryoyu test ettim ve ikincisi de çalışmalı. Kaçış karakterlerine dikkat edin, çoğu durumda greptil kullanmanın daha kolay olması gerektiğini düşünüyorum. Tabii ki, sed ile birçok ilginç şey yapabilirsiniz ve bunun için xargs ile kullanmakta ustalaşmak tercih edilebilir.
Bunu başka bir gönderiden buldum (hangisini hatırlayamıyorum) ve en zarif olmasa da, basit ve acemi bir Linux kullanıcısı bana sorun vermedi
for i in *old_str* ; do mv -v "$i" "${i/\old_str/new_str}" ; done
boşluk veya başka özel karakterleriniz varsa, \
for i in *old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done
alt dizinlerdeki dizeler için **
for i in *\*old_str\ * ; do mv -v "$i" "${i/\old_str\ /new_str}" ; done
Basit bir komut dosyası kullanmanın daha kolay bir yolu vardır:
# sudo chmod +x /bin/replace_string_files_present_dir
dosyayı gedit veya seçtiğiniz bir düzenleyicide açın, burada gedit kullanıyorum.
# sudo gedit /bin/replace_string_files_present_dir
Sonra editörde aşağıdakileri dosyaya yapıştırın
#!/bin/bash
replace "oldstring" "newstring" -- *
replace "oldstring1" "newstring2" -- *
#add as many lines of replace as there are your strings to be replaced for
#example here i have two sets of strings to replace which are oldstring and
#oldstring1 so I use two replace lines.
Dosyayı kaydedin, gedit'i kapatın , sonra terminalinizden çıkın veya kapatın ve eklediğiniz yeni komut dosyasını yükleyebilmek için başlatın.
Düzenlemek istediğiniz birden fazla dosyanızın bulunduğu dizine gidin. O zaman koş:
#replace_string_files_present_dir
Basın girip bu otomatik yerini alacak oldstring ve oldstring1 doğru bunları içeren tüm dosyalarda yeni-dizge argümanının ve newstring1 sırasıyla.
Eski dizeleri içermeyen tüm dizinleri ve dosyaları atlar.
Bu, dizenin değiştirilmesi gereken dosyalara sahip birden fazla dizininiz olması durumunda sıkıcı yazma işini ortadan kaldırmaya yardımcı olabilir. Tek yapmanız gereken bu dizinlerin her birine gitmek, ardından çalıştırmak:
#replace_string_files_present_dir
Tek yapmanız gereken, yukarıda gösterdiğim gibi tüm değiştirme dizelerini eklediğinizden veya eklediğinizden emin olmaktır:
replace "oldstring" "newstring" -- *
/ bin / replace_string_files_present_dir dosyasının sonunda .
Yeni bir değiştirme dizesi eklemek için, terminalde aşağıdakileri yazarak oluşturduğumuz komut dosyasını açmanız yeterlidir:
sudo gedit /bin/replace_string_files_present_dir
Eklediğiniz değiştirme dizelerinin sayısı konusunda endişelenmeyin, eski dize bulunmazsa bunların hiçbir etkisi olmaz.
.gitlab-ci.yml
veya a diyelim travis.yml
) dahil edilmesi için kompakt bir sürüm ister . Daha sonra yürütmek için bir komut dosyası yazma oluşan her dönüş bir anti-desen, o zaman komut dosyası oluşturma komut dosyası gerekir (ve ben çoğu zaman dağınık gider)
$ replace "From" "To" - `bul / yol / klasör / klasör-tür f`
(replace - MySQL Veritabanı Sisteminin dize değiştirme yardımcı programı)