Bazı dize verilerini bir metin dosyasına eklemek için bir Unix komutu var mı?
Gibi bir şey:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
Bazı dize verilerini bir metin dosyasına eklemek için bir Unix komutu var mı?
Gibi bir şey:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
Yanıtlar:
sed -i.old '1s;^;to be prepended;' inFile
-i
değişikliği yerinde yazar ve herhangi bir uzantı verilmişse yedek alır. (Bu durumda, .old
)1s;^;to be prepended;
;
komut sınırlayıcı olarak kullanarak ilk satırın başlangıcını verilen değiştirme dizesiyle değiştirir .\n
başa eklemeden sonra eklemek isteyebilir ; ihtiyaçlarına bağlı olarak. Düzgün çözüm.
inFile
Dizinleri yoluna dahil edebilir mi?
\n
. Önce yorumları okumalıydım. Lanet olsun.
'1s;^;my-prepended-line\;\n;'
printf '%s\n%s\n' "to be prepended" "$(cat text.txt)" >text.txt
git config --get-regex $arg | sed -r 's/\t{3}/\\n/g';
Bu dosyamda vardı ve bu, \t
ve \n
.
echo "to be prepended"$'\n'"$(cat text.txt)"
Kimsenin bundan bahsetmediğine şaşırdım.
cat <(echo "before") text.txt > newfile.txt
Bu, kabul edilen cevaptan tartışmasız daha doğaldır (bir şeyin yazdırılması ve bir ikame komutuna aktarılması sözlükbilimsel olarak sezgiseldir).
... ve Ryan'ın yukarıda söylediklerini ele geçirmek, sponge
geçici bir dosyaya ihtiyacınız yok:
sudo apt-get install moreutils
<<(echo "to be prepended") < text.txt | sponge text.txt
DÜZENLEME: Görünüşe göre bu Bourne Shell'de çalışmıyor /bin/sh
Buraya dizesi kullanarak - <<<
şunları yapabilirsiniz:
<<< "to be prepended" < text.txt | sponge text.txt
<<(echo "to be prepended") < text.txt
ve <<< "to be prepended" < text.txt
yapılarınız bash'ta çalışmaz; zsh gerektirirler.
Bu bir olasılık:
(echo "to be prepended"; cat text.txt) > newfile.txt
muhtemelen bir ara dosyada kolayca dolaşamayacaksınız.
Alternatifler (kabuk kaçarken kullanışsız olabilir):
sed -i '0,/^/s//to be prepended/' text.txt
cat <(echo "to be prepended") text.txt > newfile.txt
. Bir düşünün, benimkinin ilgili olduğundan emin değilim, bu yüzden ayrı bir cevap gönderiyorum.
Bu, çıktıyı oluşturmak için çalışacaktır. -, yankıdan boru yoluyla sağlanan standart girdi anlamına gelir.
echo -e "to be prepended \n another line" | cat - text.txt
Dosyayı yeniden yazmak için, giriş dosyasına geri yönlendirilemediğinden geçici bir dosya gereklidir.
echo "to be prepended" | cat - text.txt > text.txt.tmp
mv text.txt.tmp text.txt
text.txt
istenildiği gibi metni dosyanın başına eklemez , ancak standart çıktıda görüntüler.
Adam'ın cevabını tercih et
Sünger kullanımını kolaylaştırabiliriz . Artık geçici bir dosya oluşturup yeniden adlandırmamıza gerek yok.
echo -e "to be prepended \n another line" | cat - text.txt | sponge text.txt
Not:
Bunu yapmak, özellikle potansiyel olarak bir sembolik bağlantıyı normal bir dosya ile değiştirmek, dosya üzerinde farklı izinlerle sonuçlanmak ve dosyanın oluşturulma (doğum) tarihini değiştirmek gibi beklenmedik yan etkilere neden olabilir.
sed -i
Olduğu gibi Prens John Wesley cevap , en özgün izinleri geri de çalışır, ancak diğer sınırlamalar da geçerlidir.
İşte geçici bir dosya kullanan basit bir alternatif ( shime çözümünün yaptığı gibi tüm girdi dosyasını belleğe okumaktan kaçınır ):
{ printf 'to be prepended'; cat text.txt; } > tmp.txt && mv tmp.txt text.txt
Bir grup komutu ( { ...; ...; }
) kullanmak , 0xC0000022L'nin çözümünde olduğu gibi, subshell ( (...; ...)
) kullanmaktan biraz daha etkilidir .
Avantajlar:
Bu yeni bir metin doğrudan ilk satırına başına eklenecektir gerekip gerekmediğini kontrol etmek kolaydır veya eklenmesi gereken olmadığı gibi yeni hat (lar) (sadece ekleme \n
için printf
argüman).
sed
Çözümün aksine, girdi dosyası boşsa ( 0
bayt) çalışır.
sed
Çözelti niyet bir veya daha fazla öne eklemek için ise basitleştirilebilir bütün çizgiler (girdi dosya boş olmayan olduğunu varsayarak) mevcut içeriği:
sed
bireyin i
işlev uçlar bütün hatlar:
İle GNU sed
:
# Prepends 'to be prepended' *followed by a newline*, i.e. inserts a new line.
# To prepend multiple lines, use '\n' as part of the text.
# -i.old creates a backup of the input file with extension '.old'
sed -i.old '1 i\to be prepended' inFile
MacOS / BSD ile de çalışan taşınabilir bir varyant sed
:
# Prepends 'to be prepended' *followed by a newline*
# To prepend multiple lines, escape the ends of intermediate
# lines with '\'
sed -i.old -e '1 i\
to be prepended' inFile
'Den sonraki düz satırsonunun \
gerekli olduğunu unutmayın.
Saygıdeğer ed
POSIX yardımcı programını kullanarak :
Not:
ed
her zaman ilk olarak girdi dosyasını bir bütün olarak belleğe okur .To ilk satıra doğrudan prepend (olduğu gibi sed
girdi dosyası tamamen boş (eğer bu olmaz işi 0
) bayt):
ed -s text.txt <<EOF
1 s/^/to be prepended/
w
EOF
-s
bastırılmış ed
durum mesajları.ed
çok satırlı bir belge ( <<EOF\n...\nEOF
) olarak, yani stdin aracılığıyla sağlandığına dikkat edin ; varsayılan olarak dizge genişletme edilir (kabuk değişkenleri interpole edilir) bu belgelerin gerçekleştirilir; bunu bastırmak için açılış sınırlayıcısını alıntılayın (örneğin <<'EOF'
).1
1. satırı mevcut satır yapars
, şu anki satırda normal ifadeye dayalı bir dize değişimi gerçekleştirir sed
; Eğer içerebilir değişmez ikame metninde yeni satır, ancak olmalıdır \
öncelemeli.w
(test etmek için, yerine girdi dosyasına sonucu geri yazar w
ile ,p
sadece yazdırmak giriş dosyasını değiştirmeden, sonucu).Bir veya daha fazla tam satırı başa eklemek için :
Olduğu gibi sed
, i
işlev her zaman eklenecek metne bir satırsonu ekler.
ed -s text.txt <<EOF
0 i
line 1
line 2
.
w
EOF
0 i
0
mevcut satırı (dosyanın başlangıcını) yapar ve ekleme modunu başlatır ( i
); satır numaralarının aksi takdirde 1
-base olduğunu unutmayın ..
.Muhtemelen hiçbir şey yerleşik değildir, ancak kendi yazınızı oldukça kolay bir şekilde yazabilirsiniz, örneğin:
#!/bin/bash
echo -n "$1" > /tmp/tmpfile.$$
cat "$2" >> /tmp/tmpfile.$$
mv /tmp/tmpfile.$$ "$2"
En azından böyle bir şey ...
$$
Bununla birlikte, üretim kodu için kullanmak yetersizdir (google symlink saldırısı); ama kesinlikle statik bir dosya adından daha iyidir.
mktemp
Bazı durumlarda, başa eklenen metin yalnızca stdin'den edinilebilir. O zaman bu kombinasyon işe yarayacaktır.
echo "to be prepended" | cat - text.txt | tee text.txt
tee
Çıktıyı atlamak istiyorsanız , ekleyin > /dev/null
.
tee
clobber değil text.txt
önce cat
okumak için alır? Sanmıyorum - bu da bu çözümü dosyanın sağlığı için tehlikeli hale getirir.
lenA=1000000; yes a | head -c $lenA > a.txt; lenB=10000; b=$(yes b | head -c $lenB); echo "$b" | cat - a.txt | tee a.txt > /dev/null
. Eğer lenA
1000000 (1 Mb dosyası) ve lenB
(10Kb metin başa getirebilir) 10000, daha sonra "a.txt", "b" harfleri 20KB yazılır dosya. Bu tamamen bozuldu. Şimdi, başa eklemek için 1Mb a.txt ve 1Mb metin kullanırsanız, tee
7Gb + dosya üreten bir döngüye girerseniz, komutu durdurmak zorunda kaldım. Bu nedenle, sonucun büyük boyutlar için tahmin edilemez olduğu açıktır. Küçük boyutlarda çalışıp çalışmayacağı konusunda hiçbir bilgim yok.
Çözüm:
printf '%s\n%s' 'text to prepend' "$(cat file.txt)" > file.txt
Genişletme olmadığından bunun her tür giriş için güvenli olduğunu unutmayın. Örneğin, başa eklemek istiyorsanız !@#$%^&*()ugly text\n\t\n
, sadece çalışacaktır:
printf '%s\n%s' '!@#$%^&*()ugly text\n\t\n' "$(cat file.txt)" > file.txt
Göz önünde bulundurulması gereken son kısım, komut değiştirme sırasında dosyanın sonundaki boşlukların kaldırılmasıdır "$(cat file.txt)"
. Bunun için tüm çözüm yolları nispeten karmaşıktır. File.txt sonundaki yeni satırları korumak istiyorsanız, şuna bakın: https://stackoverflow.com/a/22607352/1091436
file.txt
argüman listesine sığabilecek olandan daha büyük olması durumunda ortaya çıkar printf
.
Kullanmanın başka bir yolu sed
:
sed -i.old '1 {i to be prepended
}' inFile
Başa eklenecek satır çok satırlıysa:
sed -i.old '1 {i\
to be prepended\
multiline
}' inFile
sed -i '1ito be prepended' inFile
- yoksa yalnızca GNU sed için izin verilir mi?
sed
, i
komutun ardından bir ters eğik çizgi ve bir satırsonu gelir ve son hariç her girdi satırı da bir ters eğik çizgiyle biter. GNU sed
, sorduğunuz satırlar boyunca kısayollara izin verir, ancak bunu yapan yalnızca GNU'dur sed
. '
Bash'de (Ubuntu'da) test edildiği gibi, üzerinden bir test dosyasıyla başlıyorsa;
echo "Original Line" > test_file.txt
yürütebilirsiniz;
echo "$(echo "New Line"; cat test_file.txt)" > test_file.txt
ya da, bash sürümü $ () için çok eskiyse, ters tikleri kullanabilirsiniz;
echo "`echo "New Line"; cat test_file.txt`" > test_file.txt
ve aşağıdaki "test_file.txt" içeriğini alın;
New Line
Original Line
Ara dosya yok, sadece bash / echo.
Oldukça basit bir başka çözüm şudur:
$ echo -e "string\n" $(cat file)
cat
Parametre genişlemesinin çift tırnak içinde olmaması, olumsuz oy için oldukça iyi bir nedendir . Bu kod, dosyanın içeriğini kelimelere böler ve bu kelimelerin her birini ayrı bir argüman olarak iletir echo
. Orijinal argüman sınırlarını kaybedersiniz, yeni satırları / sekmeleri / vb. Kaybedersiniz ve orijinal metindeki \t
ve benzeri dizeler olduğu gibi \n
tutulmak yerine sekmeler ve satırsonları ile değiştirilir.
Vi / vim'i seviyorsanız, bu sizin tarzınız olabilir.
printf '0i\n%s\n.\nwq\n' prepend-text | ed file
Bir işlev tanımlamanızı ve ardından gerektiğinde bunu içe aktarmanızı ve kullanmanızı öneririm.
prepend_to_file() {
file=$1
text=$2
if ! [[ -f $file ]] then
touch $file
fi
echo "$text" | cat - $file > $file.new
mv -f $file.new $file
}
O zaman şu şekilde kullanın:
prepend_to_file test.txt "This is first"
prepend_to_file test.txt "This is second"
Dosya içeriğiniz daha sonra:
This is second
This is first
Bir değişiklik günlüğü güncelleyicisini uygulamak için bu yaklaşımı kullanmak üzereyim.