Solaris'deki “sed -i” komutuna alternatif var mı?


11

Benim proje gibi bir dosyadaki bazı mevcut metin gibi foobazı metin ile değiştirmek için bir gereksinim var fooofoo:

abc.txt
name
foo
foo1

Bu yüzden denedim:

sed -i "s/foo/fooofoo/g" abc.txt

Ancak bu hatayı alıyorum:

sed: geçersiz seçenek - i

Kılavuzda kullanmak zorunda olduğumu buldum:

sed -i\ "s/foo/fooofoo/g" abc.txt

Ancak bu da çalışmıyor.

Alternatifler de buldum perlve awkSolaris'te bir çözüm sedçok takdir edilecektir.

Bu bash sürümünü kullanıyorum:

GNU bash, sürüm 3.2.57 (1) -çalışma (sparc-sun-solaris2.10)


Solaris 11 ve sonraki sürümlerde, /usr/gnu/bin/sed-i desteği almak için kullanın .
alanc

Yanıtlar:


15

Kullanın ed. Çoğu platformda bulunur ve dosyalarınızı yerinde düzenleyebilir.
Yana seddayanmaktadır eddesenleri değiştirmek için sözdizimi benzer:

ed -s infile <<\IN
,s/old/new/g
w
q
IN

Neden edyerine exsadece merak? (Her ikisinin de POSIX uyumlu olduğunu ve teknik özelliklere bağlı olduğumu biliyorum;))
Wildcard

1
@Wildcard - Ben tam tersini sorabilirsiniz - neden ex? Sorunuzu cevaplamak için: Asla kullanmadığımdan ex , ona aşina değilim. btw, edmevcut olan kurulumları gördüm ama ex(ama tam tersi değil) ... en dikkat çeken şey dizüstü bilgisayarım :)
don_crissti

İyi cevap. :) Cevabım: Vim'i her zaman kullandığımdan, exkomutlara çok aşinayım . Tüm viEğer iki nokta üst üste ile başlayan bir yazabilirsiniz komutlardır exkomutlar. Elbette birkaç Vim'e özgü uzantı var, ancak sadece çekirdek komut seti inanılmaz derecede güçlü ve esnektir ve kodlanmış düzenlemeler için bol miktarda bulunur.
Wildcard

Benim Manjaro sistemim var exve değil ed.
ortası

8

GNU sed'i yükleyemiyorsanız, şunu kullanın:

sed "s/foo/fooofoo/g" abc.txt >abc.tmp && mv abc.tmp abc.txt

Bu , sed çıktısını geçici bir dosyaya göndermek için yeniden yönlendirme kullanır . Sed başarıyla tamamlanırsa, bu abc.txtgeçici dosyanın üzerine yazar .

GNU sed için kaynak kodundan da görülebileceği gibi , tam olarak sed -ibunu yapar. Yani, bu kadar etkili sed -i.

Zaten var olan bir şans abc.tmpvarsa, mktempgeçici için benzersiz bir ad oluşturmak için veya benzer bir yardımcı program kullanmak isteyebilirsiniz .


Yardım için teşekkürler. Ancak solaris'te mevcut dosyayı geçici dosya oluşturmadan güncelleyebileceğimiz bir seçenek var mı?
tpsaitwal

10
Size kırmaktan nefret ediyorum, ama sed bile geçici bir dosya oluşturur. git.savannah.gnu.org/cgit/sed.git/tree/sed/sed.c#n84
Jeff Schaller

1
Sabit bağlantıları önemsemiyorsanız yapabilirsiniz - örneğime bakın. Hala geçici bir dosya var, ancak gizli (isimsiz). Geçici olmadan ed, tüm dosyayı belleğe okuduğu için kullanmanız gerekir .
Toby Speight

3

Eşdeğerini istiyorsanız, sed -i.bakoldukça basit.

GNU sed için şu komut dosyasını düşünün:

#!/bin/sh

# Create an input file to demonstrate
trap 'rm -r "$dir"' EXIT
dir=$(mktemp -d)
grep -v '[[:upper:][:punct:]]' /usr/share/dict/words | head >"$dir/foo"

# sed program - removes 'aardvark' and 'aardvarks'
script='/aard/d'

##########
# What we want to do
sed -i.bak -e "$script" "$dir"
##########

# Prove that it worked
ls "$dir"
cat "$dir/foo"

İşaretli çizgiyi basitçe

cp "$dir/foo" "$dir/foo.bak" && sed -e "$script" "$dir/foo.bak" >"$dir/foo"

Bu, varolan dosyayı yedek olarak taşır ve yeni bir dosya yazar.

Eğer eşdeğerini istiyorsak

sed -i -e "$script" "$dir"  # no backup

o zaman biraz daha karmaşıktır. Sed'in çıkışını değiştirmek için yönlendirmeden önce dosyayı standart girdi olarak okumak için açabilir, ardından bağlantısını kaldırabiliriz:

( cp "$dir/foo" "$dir/foo.bak"; exec <"$dir/foo.bak"; rm "$dir/foo.bak"; exec sed -e "$script" >"$dir/foo" )

Bunu bir alt kabukta yapıyoruz, böylece orijinal stdinimiz bundan sonra hala kullanılabilir. Girişleri değiştirmek ve alt kabuk olmadan geri dönmek mümkündür, ancak bu benim için daha net görünüyor.

Yeni bir foodosya oluşturmak yerine önce kopyalamaya dikkat ettiğimizi unutmayın - dosya birden fazla adla biliniyorsa (yani sabit bağlantıları varsa) ve bağlantıları koparmadığınızdan emin olmak istiyorsanız bu önemlidir. .


3

İlk olarak, i\bahsettiğiniz komutun , bir metin satırı eklemek için olduğunu bilmelisiniz - düzenlenen metni dosyaya geri kaydetmek için değil. Hiçbir yoktur POSIX belirtilen yolu kullanmak sedbunun için.

Ne yapabilirsiniz yapmak kullanımıdır ex, bir POSIX tarafından belirlenen :

printf '%s\n' '%s/find/replace/g' 'x' | ex file.txt

xKomut içindir "kaydet ve çık." Ayrıca kullanabilirsiniz, wqancak xdaha kısadır.

%Yedek komut araçlarının başında işareti, "tampon her satıra bu komutu uygulayın." 1,$s/find/replace/gAyrıca kullanabilirsiniz .


Arasındaki önemli bir fark exve sedolmasıdır seda, akış düzenleyicisi. Sadece sıralı olarak, satır satır çalışır. exbundan çok daha esnektir ve aslında interaktif metin dosyası düzenlemesini doğrudan yapabilirsiniz ex. Bunun hemen öncülüdür vi.


1

Kullanılabilir sedve görünür geçici dosya yok:

Ayrı bir görünür "geçici dosya" oluşturmaktan kaçınabilirsiniz :

exec 3<abc.txt
rm abc.txt
sed 's/foo/fooofoo/' <&3 >abc.txt
exec 3<&-

açıklama

Unix benzeri sistemler bu kadar kadar aslında diskten dosyanın içeriğini çıkarmayın hem dosya sistemindeki bağlantısız, ve herhangi bir işlemde açık değil. Böylece exec 3<, dosya tanımlayıcı 3, rmdosya (dosya sisteminden bağlantısı kaldırılır) okumak için kabukta dosyayı açabilirsiniz ve daha sonra sedgirdi olarak kullanılan dosya tanımlayıcı 3 ile çağrı yapabilirsiniz .

Bunun bundan çok farklı olduğuna dikkat edin :

# Does not work.
sed 's/foo/fooofoo/' <abc.txt >abc.txt

Fark, tek bir komutta yaptığınızda, kabuğun aynı dosyayı hem okuma için hem de dosyayı kısaltma seçeneğiyle yazmak için açmasıdır - hala aynı dosya olduğundan içeriği kaybedersiniz. Ancak okumak için açarsanız, o rmzaman yazmak için aynı yol adını açarsanız, aslında aynı yol adında yeni bir dosya oluşturursunuz (ancak orijinal hala açık olduğundan yeni bir inode ve disk konumunda): içerik hala kullanılabilir.

Ardından exec 3<&-, işletim sisteminin disk alanını silebilmesi (kullanılmayan olarak işaretle) için orijinal dosyayı serbest bırakan daha önce açtığınız dosya tanımlayıcısını ( özel sözdiziminin yaptığı şey) kapatabilirsiniz.

Uyarılar

Bu çözüm hakkında akılda tutulması gereken birkaç şey var:

  1. İçeriğin içinden yalnızca bir "git" elde edersiniz - bir kabuğun dosya tanımlayıcısında "araması" için taşınabilir bir yol yoktur - bu nedenle bir program içeriğin bir kısmını okuduğunda, diğer programlar yalnızca dosyanın geri kalanını görür. Ve sedtüm dosyayı okuyacaktır.

  2. Kabuk / script / sed'iniz bitmeden öldürülürse orijinal dosyanızın kaybolması ihtimali düşüktür.


Açık olmak gerekirse, @TobySpeight cevabının sonunda zaten bu çözümün bir örneğini yayınladı, ancak daha derinlemesine bir ayrıntı kullanabileceğini düşündüm.
mtraceur

Downvoter'a: Sadece bir downvote bırakmak kendiniz hakkında iyi hissetmenizi sağlar, ancak bu cevapla ilgili sorunlarınız, nasıl geliştirilebileceğiniz vb. .
mtraceur

belki perl -i kullanabilirsiniz
c4f4t0r

@ c4f4t0r: Geç cevap için özür dilerim: Evet, perl -iiyi bir seçenek. Soru sed, çözüm bulmanın aksine perlve awkzaten bulduklarından bahsettiklerinden farklı olarak, Solaris ile uyumlu bir çözüm talep etti. Ayrıca, cevabım esas olarak, diğer cevaplardan herhangi birinde bilmek ve eksik olduğunu düşündüğüm bir şey eklemeyi amaçladı.
mtraceur
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.