Bu muhtemelen karmaşık bir çözümdür .
">>" gibi basit bir operatör arıyorum, ancak önceden harcamak için.
Korkarım yok. Gibi bir şey yapmam gerekecek
mv myfile tmp kedi kafam tmp> dosyam
Daha akıllı bir şey var mı?
Bu muhtemelen karmaşık bir çözümdür .
">>" gibi basit bir operatör arıyorum, ancak önceden harcamak için.
Korkarım yok. Gibi bir şey yapmam gerekecek
mv myfile tmp kedi kafam tmp> dosyam
Daha akıllı bir şey var mı?
Yanıtlar:
Aşağıdaki hack , işe yarayan ve çok sayıda olumlu oy alan hızlı bir yanıttı. Sonra, soru daha popüler hale geldikçe ve daha fazla zaman geçtikçe, öfkeli insanlar bunun işe yaradığını ama tuhaf şeyler olabileceğini ya da hiç işe yaramadığını bildirmeye başladı, bu yüzden bir süre öfkeyle reddedildi. Ne kadar eğlenceli.
Çözüm, sisteminizdeki dosya tanımlayıcılarının tam olarak uygulanmasından yararlanır ve uygulama, boşluklar arasında önemli ölçüde farklılık gösterdiğinden, başarısı tamamen sisteme bağlıdır, kesinlikle taşınabilir değildir ve belirsiz bir şekilde önemli olan hiçbir şey için güvenilmemelidir.
Şimdi, tüm bunların dışında cevap şuydu:
Dosya ( exec 3<> yourfile
) için başka bir dosya tanımlayıcı yaratmak ve buna ( ) >&3
yazmak, aynı dosya üzerinde okuma / yazma ikileminin üstesinden gelecektir . Benim için awk ile 600K dosyalarda çalışır. Ancak aynı numarayı 'kedi' kullanarak denemek başarısız olur.
Önpendajı bir değişken olarak awk ( -v TEXT="$text"
) ' ye geçirmek, bu hileyi' sed 'ile yapmayı engelleyen birebir alıntı probleminin üstesinden gelir.
#!/bin/bash
text="Hello world
What's up?"
exec 3<> yourfile && awk -v TEXT="$text" 'BEGIN {print TEXT}{print}' yourfile >&3
Bu hala bir geçici dosya kullanıyor, ancak en azından bir satırda:
echo "text" | cat - yourfile > /tmp/out && mv /tmp/out yourfile
-
Sonra ne oluyor cat
?
echo -n "text"
yourfile
bir sembolik bağlantı ise , bu istediğinizi yapmayacaktır.
echo '0a
your text here
.
w' | ed some_file
ed, Standart Düzenleyicidir! http://www.gnu.org/fun/jokes/ed.msg.html
0r header.file
echo -e '0a\nyour text here\n.\nw' | ed some_file
John Mee: Metodunuzun çalışacağı garanti edilmez ve 4096 bayttan fazla malzeme eklerseniz muhtemelen başarısız olacaktır (en azından gnu awk ile olan budur, ancak diğer uygulamaların da benzer kısıtlamaları olacağını düşünüyorum). Sadece bu durumda başarısız olmakla kalmayacak, aynı zamanda kendi çıktısını okuyacağı sonsuz bir döngüye girecek ve böylece mevcut alan dolana kadar dosyanın büyümesini sağlayacaktır.
Kendiniz deneyin:
exec 3<>myfile && awk 'BEGIN{for(i=1;i<=1100;i++)print i}{print}' myfile >&3
(uyarı: bir süre sonra onu sonlandırın yoksa dosya sistemini doldurur)
Dahası, dosyaları bu şekilde düzenlemek çok tehlikelidir ve çok kötü bir tavsiye, sanki dosya düzenlenirken (çökme, disk dolu) dosyada tutarsız bir durumda kalmanız neredeyse garantidir.
Geçici dosya olmadan mümkün değil, ama işte oneliner
{ echo foo; cat oldfile; } > newfile && mv newfile oldfile
Geçici dosyalar olmadan yapmak için ed veya perl gibi diğer araçları kullanabilirsiniz.
Geçici dosyayı mktemp gibi bir yardımcı program kullanarak güvenli bir şekilde oluşturmanın , en azından komut dosyası kök ayrıcalıklarıyla çalıştırılacaksa, genellikle iyi bir fikir olduğunu belirtmekte fayda var . Örneğin şunları yapabilirsiniz (yine bash'da):
(tmpfile=`mktemp` && { echo "prepended text" | cat - yourfile > $tmpfile && mv $tmpfile yourfile; } )
Kontrol ettiğiniz bilgisayarlarda buna ihtiyacınız varsa, "moreutils" paketini kurun ve "sünger" kullanın. O zaman şunları yapabilirsiniz:
cat header myfile | sponge myfile
{ echo "prepended text"; cat myfile } | sponge myfile
Heredoc bash kullanarak bir tmp dosyası ihtiyacını ortadan kaldırabilirsiniz:
cat <<-EOF > myfile
$(echo this is prepended)
$(cat myfile)
EOF
Bu işe yarar çünkü $ (cat myfile), bash betiği değerlendirildiğinde, yönlendirmeli cat çalıştırılmadan önce değerlendirilir.
Düzenlemek istediğiniz dosyanın my.txt olduğunu varsayarsak
$cat my.txt
this is the regular file
Başına eklemek istediğiniz dosya başlıktır
$ cat header
this is the header
Başlık dosyasında son bir boş satır olduğundan emin olun.
Şimdi başına ekleyebilirsiniz
$cat header <(cat my.txt) > my.txt
İle sonuçlanırsın
$ cat my.txt
this is the header
this is the regular file
Bildiğim kadarıyla bu sadece 'bash'da çalışıyor.
this is the header
My.txt dosyasında iki satır ile bitirdim. Bash'i güncelledikten sonra bile 4.3.42(1)-release
aynı sonucu alıyorum.
<(...)
) işlemdeki komutun yazdığı bir FIFO (boru) oluşturur, bu nedenle baştan tam olarak okunacağının garantisi yokturmy.txt
, bu olmadan bu teknik çalışmaz.
Kabuk komut dosyasında zorlaşan şeyleri yapmaya başladığınızda, betiği "uygun" bir kodlama dilinde (Python / Perl / Ruby / vb.)
Dosyaya bir satırın önceden eklenmesine gelince, bunu borulama yoluyla yapmak mümkün değildir, çünkü herhangi bir şey yaptığınızda cat blah.txt | grep something > blah.txt
, yanlışlıkla dosyayı kapatır . Yükleyebileceğiniz adında küçük bir yardımcı program komutu vardır sponge
(yaparsınız cat blah.txt | grep something | sponge blah.txt
ve dosyanın içeriğini arabelleğe alır, sonra dosyayı dosyaya yazar). Geçici bir dosyaya benzer, ancak bunu açıkça yapmanız gerekmez. ama bunun Perl'den "daha kötü" bir gereklilik olduğunu söyleyebilirim.
Bunu awk veya benzeri bir yöntemle yapmanın bir yolu olabilir, ancak kabuk-komut dosyası kullanmanız gerekiyorsa, geçici bir dosyanın açık arayla en kolay (/ yalnızca?) Yol olduğunu düşünüyorum.
Daniel Velkov'un önerdiği gibi, tee kullanın.
Bana göre, bu basit ve akıllı bir çözüm:
{ echo foo; cat bar; } | tee bar > /dev/null
DÜZENLEME: Bu bozuk. Kedi ve tişört içeren bir dosyanın başına eklerken tuhaf davranışları görün
Üzerine yazma sorununun geçici çözümü şudur tee
:
cat header main | tee main > /dev/null
Çoğunlukla eğlence / kabuk golf için, ancak
ex -c '0r myheader|x' myfile
hile yapacak ve ardışık düzenler veya yeniden yönlendirme yok. Tabii ki, vi / ex gerçekten etkileşimli olmayan kullanım için değildir, bu nedenle vi kısaca yanıp sönecektir.
Neden sadece ed komutunu kullanmıyorsunuz (burada fluffle tarafından önerildiği gibi)?
ed tüm dosyayı belleğe okur ve otomatik olarak yerinde dosya düzenlemesi yapar!
Yani, dosyanız o kadar büyük değilse ...
# cf. "Editing files with the ed text editor from scripts.",
# http://wiki.bash-hackers.org/doku.php?id=howto:edit-ed
prepend() {
printf '%s\n' H 1i "${1}" . wq | ed -s "${2}"
}
echo 'Hello, world!' > myfile
prepend 'line to prepend' myfile
Yine başka bir geçici çözüm, Jürgen Hötzel tarafından önerildiği gibi sed 's / c / d /' myFile'dan myFile'a Redirect çıktısında açık dosya tanıtıcılarını kullanmak olabilir.
echo cat > manipulate.txt
exec 3<manipulate.txt
# Prevent open file from being truncated:
rm manipulate.txt
sed 's/cat/dog/' <&3 > manipulate.txt
Elbette tüm bunlar tek bir satıra yazılabilir.
Sabit metnin başına eklemek için cb0'ın "geçici dosya yok" çözümünün bir varyantı:
echo "text to prepend" | cat - file_to_be_modified | ( cat > file_to_be_modified )
Yine bu, kedinin girdi ve çıktı için aynı dosyaya sahip olmayı reddetmesini önlemek için alt kabuk uygulamasına - (..) - dayanır.
Not: Bu çözümü beğendim. Ancak, Mac'imde orijinal dosya kayboldu (olmaması gerektiğini düşündü ama kayboluyor). Bu, çözümünüzü şu şekilde yazarak düzeltilebilir: echo "başa eklenecek metin" | cat - file_to_be_modified | cat> tmp_file; mv tmp_file file_to_be_modified
İşte keşfettiğim şey:
echo -e "header \n$(cat file)" >file
sed -i -e '1rmyheader' -e '1{h;d}' -e '2{x;G}' myfile
UYARI: OP'nin ihtiyaçlarını karşılamak için biraz daha fazla çalışmaya ihtiyaç vardır.
Kaygılarına rağmen @shixilun tarafından sed yaklaşımının işe yaramasını sağlamanın bir yolu olmalı. Bir dosyayı sed ikame dizesine okurken boşluktan kaçmak için bir bash komutu olmalıdır (örneğin, satırsonu karakterlerini '\ n' ile değiştirin. Kabuk komutları vis
ve cat
yazdırılamayan karakterlerle ilgilenebilir, ancak beyaz boşluklarla ilgilenemez, bu nedenle bu OP'leri çözmez sorun:
sed -i -e "1s/^/$(cat file_with_header.txt)/" file_to_be_prepended.txt
Bu SO cevabı gibi kabuğu ve sed'i mutlu tutmak için, yerine bir satır devam karakteri () ve belki de ardından bir & ile eklenmesi gereken, yedek komut dosyasındaki ham satırsonları nedeniyle başarısız olur
sed
global olmayan arama-değiştirme komutları için boyut sınırı 40K'dır (örüntüden sonra / g yok), bu nedenle anonim olan awk'nin korkutucu arabellek taşması sorunlarından kaçınılır.
sed -i -e "1s/^/new first line\n/" old_file.txt
Aşağıdakilerle bir çözüm printf
:
new_line='the line you want to add'
target_file='/file you/want to/write to'
printf "%s\n$(cat ${target_file})" "${new_line}" > "${target_file}"
Şunları da yapabilirsiniz:
printf "${new_line}\n$(cat ${target_file})" > "${target_file}"
Ancak bu durumda %
, yorumlanabileceği ve sonuçlarınızı altüst edebileceği için, hedef dosyanın içeriği dahil hiçbir yerde olmadığından emin olmalısınız .
echo
daha güvenli bir seçenek gibi görünüyor. echo "my new line\n$(cat my/file.txt)" > my/file.txt
${new_line}
hedef dosyadaki yüzdeler hakkında uyardınız
Perl komut satırını kullanabilirsiniz:
perl -i -0777 -pe 's/^/my_header/' tmp
-İ dosyanın bir satır içi değişimini oluşturacak ve -0777 tüm dosyayı bulandıracak ve ^ ile yalnızca başlangıcı eşleştirecektir. -pe tüm satırları yazdırır
Veya my_header bir dosyaysa:
perl -i -0777 -pe 's/^/`cat my_header`/e' tmp
/ E'nin değiştirmede bir kod değerlendirmesine izin vereceği yer.
Ben sevmeye başladım fluffle en @ ed yaklaşımı iyi. Sonuçta, herhangi bir aracın komut satırı anahtarları ile komut dosyası içeren düzenleyici komutları esasen burada aynı şeydir; komut dosyalı bir düzenleyici çözümünün "temizliğinin" daha az olduğunu veya olmadığını görmemek.
Mesajları işlemek için bir .git/hooks/prepare-commit-msg
depo içi .gitmessage
dosyanın başına eklenen tek satırlık yazım :
echo -e "1r $PWD/.gitmessage\n.\nw" | ed -s "$1"
Örnek .gitmessage
:
# Commit message formatting samples:
# runlevels: boot +consolekit -zfs-fuse
#
Bunun 1r
yerine yapıyorum 0r
, çünkü bu, orijinal şablondan dosyanın üstüne boş yazmaya hazır satırı bırakacak. .gitmessage
O zaman üstüne boş bir satır koymayın , sonunda iki boş satırla karşılaşacaksınız. -s
ed'in teşhis bilgisi çıktısını bastırır.
Bunu yapmakla bağlantılı olarak, vim-buff'lar için şunlara sahip olmanın da iyi olduğunu keşfettim :
[core]
editor = vim -c ':normal gg'
Bence bu, ed'in en temiz çeşidi:
cat myheader | { echo '0a'; cat ; echo -e ".\nw";} | ed myfile
işlev olarak:
function prepend() { { echo '0a'; cat ; echo -e ".\nw";} | ed $1; }
cat myheader | prepend myfile
BASH'de komut dosyası yazıyorsanız, aslında, yalnızca şunları yayınlayabilirsiniz:
kedi - dosyanız / tmp / dışarı && mv / tmp / dosyanızın dışına
Aslında bu, kendi sorunuza gönderdiğiniz Karmaşık Örnek'de.
cat - yourfile <<<"text" > /tmp/out && mv /tmp/out yourfile
, ancak bu benim cevabımdan yeterince farklı, kendi cevabı olması gerekiyor.
IMHO tutarlı ve güvenilir olursa olsun iki dosyanın boyutları çalışacağına dair hiçbir kabuk çözümüdür (ve asla biri olacak) myheader
ve myfile
. Bunun nedeni, bunu geçici bir dosyada yinelemeden (ve kabuğun sessizce geçici bir dosyaya tekrarlamasına izin vermeden, örneğin exec 3<>myfile
, borulama tee
vb. Yapılar aracılığıyla yapmak istemenizdir .
Aradığınız "gerçek" çözüm, dosya sistemi ile uğraşmak zorundadır ve bu nedenle kullanıcı alanında mevcut değildir ve platforma bağlı olacaktır: kullanımdaki dosya sistemi işaretçisini dosya sistemi işaretçisinin myfile
mevcut değerine göre değiştirmenizi istiyorsunuz için myheader
ve dosya sisteminde yerini EOF
ait myheader
tarafından işaret şimdiki dosya sistemi adresine bir zincirleme bağlantı ile myfile
. Bu önemsiz değildir ve açıkçası süper kullanıcı olmayanlar tarafından yapılamaz ve muhtemelen süper kullanıcı tarafından da yapılamaz ... İnode ile oynayın, vb.
Yine de, döngü cihazlarını kullanarak bunu az çok taklit edebilirsiniz. Örneğin bu SO başlığına bakın .
mktemp
? Daha sonra her zaman geçici dosyayı temizleyebilirsiniz ...