Metni bir dosyaya eklemek için Unix komutu


126

Bazı dize verilerini bir metin dosyasına eklemek için bir Unix komutu var mı?

Gibi bir şey:

prepend "to be prepended" text.txt

tek bir komut mu arıyorsunuz yoksa küçük bir betik / takma ad komutu tamam mı?
Levon

2
Tüm cevapları birleştirirseniz, muhtemelen en kısa yol budur:<<(echo "to be prepended") < text.txt | sponge text.txt
Sridhar Sarnobat

Bu soru gerçekten birçok insanda yaratıcılığı ortaya çıkardı!
Richard Jessop

Yanıtlar:


111
sed -i.old '1s;^;to be prepended;' inFile
  • -ideğ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 .

19
Eğer komuta bir açıklama ekleyebilirseniz, sed'in işleyişine pek aşina olmayan başkaları için faydalı olacaktır. OP \nbaşa eklemeden sonra eklemek isteyebilir ; ihtiyaçlarına bağlı olarak. Düzgün çözüm.
Levon

Evet, açıklama harika olur. inFileDizinleri yoluna dahil edebilir mi?
zakdances

3
@Levon Tamamen bir \n. Önce yorumları okumalıydım. Lanet olsun.
chishaku

Benim durumumda, '1s;^;my-prepended-line\;\n;'
baştaki

5
'\ N' yalnızca GNU sed için çalıştığını, BSD için çalışmadığını (OSX, FreeBSD vb. Gibi) unutmayın.
Bunlarla

164
printf '%s\n%s\n' "to be prepended" "$(cat text.txt)" >text.txt

2
Tek satırda ve orijinal metin dosyasında! Bu doğru ve basit cevaptır. Ek yeni satırın \ n echo -e "başına eklenmesini öneriyorum \ n $ (cat text.txt)"> text.txt
VincentPerrin.com

32
Bu çözümde sorunlar var ... "\ n" oluşumlarını gerçek yeni satırlara dönüştürüyor ... "\ n" içeren dizeleri olan bir kod dosyasının başına ekliyorsanız sorunludur.
Paul Go

1
git config --get-regex $arg | sed -r 's/\t{3}/\\n/g';Bu dosyamda vardı ve bu, \tve \n.
hIpPy

8
Bu (1) tüm dosyayı belleğe yükler ve (2) tüm dosyayı tek bir komut satırı argümanına yapıştırır. Basit şeyler için iyidir, ancak sınırlamalara dikkat edin.
jwd

2
Son denediğimde, kedinin üzerine yazılmadan önce text.txt'nin tüm içeriğini okuyamadığı çok büyük dosyalarda bunun bozulacağına inanıyorum. Yankı üzerindeki -e seçeneği bir sorunsa, bash veya echo "to be prepended"$'\n'"$(cat text.txt)"
do'da

44

Süreç Değiştirme

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, spongegeç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


Here String (yalnızca zsh)

Buraya dizesi kullanarak - <<<şunları yapabilirsiniz:

<<< "to be prepended" < text.txt | sponge text.txt

3
Bu cevap benim için kazanan. Sadece yerleşiklerle basit ve ulaşılabilir. İyi iş!
PiersyP

1
@PiersyP Katılıyorum! Bu çok yardımcı oldu, teşekkürler Sridhar-Sarnobat.

Sorun 2 dosya değil 1 dosya olmasıdır. Yani cevabın ilk satırı gerçekten işe yaramıyor. Son sıra işe yarayabilir (ancak sünger gerektirir).
VasiliNovikov

1
Sünger ne işe yarar?
Hemanta

1
Sizin <<(echo "to be prepended") < text.txtve <<< "to be prepended" < text.txtyapılarınız bash'ta çalışmaz; zsh gerektirirler.
Anders Kaseorg

32

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

Strateji 1) buradaki cevaplar arasında en sezgisel olanıdır. Ve hafif bir varyasyonu: 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.
Sridhar Sarnobat

1
İlk yöntem dosya izinlerini korumaz
Xlsx

İzinleri korumanın tek yolu sünger kullanmaktır
Sridhar Sarnobat

20

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

2
bu, text.txtistenildiği gibi metni dosyanın başına eklemez , ancak standart çıktıda görüntüler.
Levon

1
bu kesinlikle "başa eklenecek" i ve ardından "text.txt" içeriğini yazdırır. Ancak metnin dosyanın başına eklenmesini istiyorum
One Two Three

1
ve ya çok satırlı bir metne sahipsem? Yeni satır karakterini oraya nasıl koyarım?
One Two Three

Bu harika olurdu ama bash bundan hoşlanmıyor: $ echo RewriteBase / | cat - web / .htaccess> web / .htaccess cat: web / .htaccess: girdi dosyası çıktı dosyasıdır
geek-merlin

14

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

bu benim için çalışan tek çözümdü. sunucumun adının spongebob olması yeterince komik.
Ömer An

11

Girdi dosyasını değiştirmek kabul edilebilirse :

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 -iOlduğ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 \niçin printfargüman).

  • sedÇözümün aksine, girdi dosyası boşsa ( 0bayt) ç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:

sedbireyin iiş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.


Girdi dosyasının yerinde düzenlenmesi gerekiyorsa (tüm öznitelikleriyle inode'unu koruyarak):

Saygıdeğer edPOSIX yardımcı programını kullanarak :

Not:

  • edher zaman ilk olarak girdi dosyasını bir bütün olarak belleğe okur .

To ilk satıra doğrudan prepend (olduğu gibi sedgirdi dosyası tamamen boş (eğer bu olmaz işi 0) bayt):

ed -s text.txt <<EOF
1 s/^/to be prepended/
w
EOF
  • -sbastırılmış eddurum mesajları.
  • Komutların nasıl 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 yapar
  • işlev s, ş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 wile ,psadece 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, iişlev her zaman eklenecek metne bir satırsonu ekler.

ed -s text.txt <<EOF
0 i
line 1
line 2
.
w
EOF
  • 0 i0mevcut 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 .
  • Aşağıdaki satırlar , kendi satırında ile biten, mevcut satırdan önce eklenecek metindir ..

7

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 ...


6
$$ (geçerli PID) geçici dosya adının bir parçası olarak kullanmak için +1. Genel kullanım için bir komut dosyası oluşturuyorsanız, bu, başka bir kullanıcının aynı komut dosyasını aynı anda çalıştırarak geçici dosyanın üzerine yazmasını engelleyecektir.
E Brown

3
$$Bununla birlikte, üretim kodu için kullanmak yetersizdir (google symlink saldırısı); ama kesinlikle statik bir dosya adından daha iyidir.
üçlü

1
sadece kullanmktemp
mewa

7

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.


Bu cevabı gerçekten beğendim. Bunu yapmanın çok temiz ve net bir yolu. Tee kullanımı, çıktıyı girdi dosyasına katlamaya çalışmak sorununa doğal bir çözümdür. Ayrıca yeniden adlandırma ile hack yok. Yeni bir dosya oluşturmadığı için şu anda en yüksek oyu alan çözümden daha iyi. Bu, temelde eklemek yerine ön harcama için >> konumuna en yakın olanıdır.
DC2

Bu açık ara en iyi ve en temiz cevap.
nerdoc

6
Garantisi var mı teeclobber değil text.txtönce catokumak için alır? Sanmıyorum - bu da bu çözümü dosyanın sağlığı için tehlikeli hale getirir.
Jonathan Leffler

3
@JonathanLeffler muhtemelen hayır. Testten bu kodu çalıştı: 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 lenA1000000 (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, tee7Gb + 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.
VasiliNovikov

3
Kavramsal terimlerle ifade etmek gerekirse: Bu komut, girdi dosyası , günümüzde tipik olarak 64 KB olan sisteminizin boru hattı arabellek boyutundan daha büyük olursa veri kaybına neden olacaktır .
mklement 0

7

Çö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


Sevdim. Süper taşınabilir ve yeni bir dosya oluşturmaya gerek yok. Teşekkürler!
pyb

1
Bununla ilgili tek sorun, içeriğinin file.txtargüman listesine sığabilecek olandan daha büyük olması durumunda ortaya çıkar printf.
Jonathan Leffler

6

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

Neden olmasın sed -i '1ito be prepended' inFile- yoksa yalnızca GNU sed için izin verilir mi?
kullanıcı bilinmiyor

@userunknown: Standart olarak sed, ikomutun 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. '
Jonathan Leffler

3

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.


2
en iyi yanıt, bu tek satırlık yazıyı dosyamı şu yanıtı kullanarak döndürmek için yazdım: for i için $ (<dosya2.txt); do echo "$ (echo $ i; cat dosya.txt)"> dosya.txt; yapılan;
Aurangzeb

2

Oldukça basit bir başka çözüm şudur:

    $ echo -e "string\n" $(cat file)

Bu benim için çalıştı ... sadece küçük bir değişiklik, girdi dosyasından çoklu satırları korumak için onu tırnak içine almanız gerekir, böylece şöyle bir şey: echo -e "string \ n" "$ (cat ~ / file.txt) "> ~ / file.txt;
Craig Wayne

2
catParametre 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 \tve benzeri dizeler olduğu gibi \ntutulmak yerine sekmeler ve satırsonları ile değiştirilir.
Charles Duffy

1

Vi / vim'i seviyorsanız, bu sizin tarzınız olabilir.

printf '0i\n%s\n.\nwq\n' prepend-text | ed file

0
# create a file with content..
echo foo > /tmp/foo
# prepend a line containing "jim" to the file
sed -i "1s/^/jim\n/" /tmp/foo
# verify the content of the file has the new line prepened to it
cat /tmp/foo

0

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.

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.