Perintah Unix untuk menambahkan teks ke file

126

Apakah ada perintah Unix untuk menambahkan beberapa data string ke file teks?

Sesuatu seperti:

prepend "to be prepended" text.txt
Satu dua tiga
sumber
apakah Anda mencari satu perintah, atau apakah perintah skrip / alias kecil oke?
Levon
2
Jika Anda menggabungkan semua jawaban, ini mungkin cara yang paling kompak:<<(echo "to be prepended") < text.txt | sponge text.txt
Sridhar Sarnobat
Pertanyaan ini benar-benar membangkitkan kreativitas banyak orang!
Richard Jessop

Jawaban:

111
sed -i.old '1s;^;to be prepended;' inFile
  • -imenulis perubahan di tempat dan membuat cadangan jika ada ekstensi yang diberikan. (Dalam hal ini, .old)
  • 1s;^;to be prepended;mengganti awal baris pertama dengan string pengganti yang diberikan, menggunakan ;sebagai pembatas perintah.
Pangeran John Wesley
sumber
19
Jika Anda bisa menambahkan beberapa penjelasan dengan perintah itu akan membantu orang lain yang tidak begitu akrab dengan cara kerja sed. OP mungkin ingin memasukkan di \nsetelah prepend; tergantung kebutuhan mereka. Solusi yang rapi.
Levon
Ya, penjelasannya akan bagus. Bisakah inFiledirektori include di jalurnya?
zakdances
3
@Levon Saya benar-benar ingin memasukkan file \n. Seharusnya sudah baca komentarnya dulu. Sial.
chishaku
Dalam kasus saya, saya ingin memiliki titik koma di akhir baris yang ditambahkan sebelumnya, jadi saya pergi dengan'1s;^;my-prepended-line\;\n;'
SamGamgee
5
Perhatikan bahwa '\ n' hanya berfungsi untuk GNU sed, bukan BSD (seperti OSX, FreeBSD, dll.). Untuk lebih portabel dengan mereka, lihat: stackoverflow.com/questions/1421478/…
jwd
164
printf '%s\n%s\n' "to be prepended" "$(cat text.txt)" >text.txt
shime
sumber
2
Dalam satu baris dan dalam file teks asli! Ini adalah jawaban sederhana yang benar. Saya menyarankan baris baru tambahan \ n echo -e "diawali dengan \ n $ (cat text.txt)"> text.txt
VincentPerrin.com
32
Solusi ini bermasalah ... ini mengubah kemunculan "\ n" menjadi baris baru yang sebenarnya ... bermasalah jika Anda membuat prepending ke file kode dengan string yang berisi "\ n".
Paul Go
1
Saya memiliki ini di file saya git config --get-regex $arg | sed -r 's/\t{3}/\\n/g';dan ini kacau karena mengubah \tdan \n.
hIpPy
8
Ini (1) memuat seluruh file ke dalam memori, dan (2) menempelkan seluruh file ke dalam argumen baris perintah tunggal. Baik untuk hal-hal sederhana, tetapi waspadalah terhadap batasannya.
jwd
2
Terakhir saya mencoba, saya yakin ini akan merusak file yang sangat besar, di mana kucing gagal membaca seluruh konten text.txt sebelum ditimpa. Jika opsi -e pada echo menjadi masalah, Anda dapat mengutip baris baru di bash atau doecho "to be prepended"$'\n'"$(cat text.txt)"
jbo5112
44

Proses Substitusi

Saya terkejut tidak ada yang menyebutkan ini.

cat <(echo "before") text.txt > newfile.txt

yang bisa dibilang lebih alami daripada jawaban yang diterima (mencetak sesuatu dan menyalurkannya ke dalam perintah substitusi secara leksikografis berlawanan dengan intuisi).

... dan membajak apa yang dikatakan ryan di atas, dengan spongeAnda tidak memerlukan file sementara:

sudo apt-get install moreutils
<<(echo "to be prepended") < text.txt | sponge text.txt

EDIT: Sepertinya ini tidak berfungsi di Bourne Shell /bin/sh


Di sini String (hanya zsh)

Menggunakan here-string - <<<, Anda dapat melakukan:

<<< "to be prepended" < text.txt | sponge text.txt
Sridhar Sarnobat
sumber
3
Jawaban ini adalah pemenangnya bagi saya. Sederhana dan dapat dicapai hanya dengan bawaan. Kerja bagus!
PiersyP
1
@PiersyP Saya setuju! Ini banyak membantu, terima kasih Sridhar-Sarnobat.
Masalahnya ada 1 file, bukan 2 file. Jadi baris pertama jawabannya tidak benar-benar berfungsi. Baris terakhir mungkin berhasil (tetapi membutuhkan spons).
VasiliNovikov
1
Apa fungsi spons?
Hemanta
1
Anda <<(echo "to be prepended") < text.txtdan <<< "to be prepended" < text.txtkonstruksi tidak berfungsi dalam bash; mereka membutuhkan zsh.
Anders Kaseorg
32

Ini adalah satu kemungkinan:

(echo "to be prepended"; cat text.txt) > newfile.txt

Anda mungkin tidak akan dengan mudah menggunakan file perantara.

Alternatif (bisa merepotkan dengan keluarnya shell):

sed -i '0,/^/s//to be prepended/' text.txt
0xC0000022L
sumber
Strategi 1) adalah jawaban paling intuitif di sini, saya rasa. Dan sedikit variasi: cat <(echo "to be prepended") text.txt > newfile.txt . Kalau dipikir-pikir, saya tidak yakin milik saya terkait, jadi saya memposting jawaban terpisah.
Sridhar Sarnobat
1
Metode pertama tidak akan mempertahankan izin file
Xlsx
Satu-satunya cara untuk mempertahankan izin adalah dengan menggunakan spons
Sridhar Sarnobat
20

Ini akan bekerja untuk membentuk keluaran. Itu - berarti input standar, yang disediakan melalui pipa dari echo.

echo -e "to be prepended \n another line" | cat - text.txt

Untuk menulis ulang file, file sementara diperlukan karena tidak dapat menyalurkan kembali ke file input.

echo "to be prepended" | cat - text.txt > text.txt.tmp
mv text.txt.tmp text.txt
Adam
sumber
2
ini tidak menambahkan teks ke file text.txtseperti yang diminta, tetapi menampilkannya di stdout. Output dapat disalurkan ke file yang berbeda jika itu berfungsi untuk OP
Levon
1
ini pasti akan mencetak "untuk ditambahkan" dan kemudian konten "text.txt". Tapi saya ingin teks itu ditambahkan ke file
One Two Three
1
dan bagaimana jika saya memiliki teks banyak baris? Bagaimana cara menempatkan karakter baris baru di sana?
Satu Dua Tiga
Ini akan keren tapi bash tidak menyukainya: $ echo RewriteBase / | cat - web / .htaccess> web / .htaccess cat: web / .htaccess: file input adalah file output
geek-merlin
14

Lebih suka jawaban Adam

Kita bisa mempermudah penggunaan spons . Sekarang kita tidak perlu membuat file sementara dan mengganti namanya dengan

echo -e "to be prepended \n another line" | cat - text.txt | sponge text.txt
ryan
sumber
ini adalah satu-satunya solusi yang berhasil untuk saya. cukup lucu bahwa nama server saya adalah spongebob.
Ömer An
10

Jika bisa diganti file input:

catatan:

  • Melakukannya mungkin memiliki efek samping yang tidak terduga, terutama berpotensi mengganti symlink dengan file biasa, berakhir dengan izin yang berbeda pada file tersebut, dan mengubah tanggal pembuatan (lahir) file.

  • sed -i, seperti dalam jawaban Pangeran John Wesley , mencoba untuk setidaknya memulihkan izin asli, tetapi batasan lain juga berlaku.

Berikut adalah alternatif sederhana yang menggunakan file sementara (ini menghindari membaca seluruh file input ke dalam memori seperti yang dilakukan solusi shime ):

{ printf 'to be prepended'; cat text.txt; } > tmp.txt && mv tmp.txt text.txt

Menggunakan perintah grup ( { ...; ...; }) sedikit lebih efisien daripada menggunakan subkulit ( (...; ...)), seperti dalam solusi 0xC0000022L .

Keunggulannya adalah:

  • Sangat mudah untuk mengontrol apakah teks baru harus langsung ditambahkan ke baris pertama atau apakah harus disisipkan sebagai baris baru (cukup tambahkan \nke printfargumen).

  • tidak seperti sed solusinya, ini berfungsi jika file input kosong ( 0byte).


Itu sed solusi dapat disederhanakan jika tujuannya adalah untuk tambahkan satu atau lebih seluruh baris dengan isi yang ada (dengan asumsi file input tidak kosong):

sed's i menyisipkan fungsi seluruh baris:

Dengan 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

Varian portabel yang juga berfungsi dengan macOS / BSD 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

Perhatikan bahwa baris baru literal setelah \ diperlukan.


Jika file input harus diedit pada tempatnya (mempertahankan inode dengan semua atributnya):

Menggunakan Yang Mulia ed utilitas POSIX yang :

catatan:

  • edselalu membaca file input secara keseluruhan ke dalam memori terlebih dahulu.

Untuk menambahkan langsung ke baris pertama (seperti sed, ini tidak akan berfungsi jika file input benar-benar kosong ( 0byte)):

ed -s text.txt <<EOF
1 s/^/to be prepended/
w
EOF
  • -s tertindas edpesan status yang .
  • Perhatikan bagaimana perintah disediakan edsebagai multi-baris here-document ( <<EOF\n...\nEOF), yaitu melalui stdin ; secara default ekspansi tali yang dilakukan di dokumen tersebut (variabel shell yang diinterpolasi); mengutip pembatas pembukaan untuk menekannya (misalnya,<<'EOF' ).
  • 1 menjadikan baris pertama sebagai baris saat ini
  • fungsi smelakukan substitusi string berbasis regex pada baris saat ini, seperti sed; Anda dapat menyertakan baris baru literal dalam teks substitusi, tetapi baris tersebut harus di- \escape.
  • wmenulis hasilnya kembali ke file input (untuk pengujian, ganti wdengan ,puntuk hanya mencetak hasil, tanpa mengubah file input).

Untuk menambahkan satu atau lebih baris penuh :

Seperti halnya sed, ifungsi tersebut selalu menambahkan baris baru ke teks yang akan disisipkan.

ed -s text.txt <<EOF
0 i
line 1
line 2
.
w
EOF
  • 0 imembuat 0(awal file) baris saat ini dan memulai mode insert ( i); perhatikan bahwa nomor baris 1didasarkan sebaliknya .
  • Baris berikut adalah teks untuk disisipkan sebelum baris saat ini, diakhiri dengan .barisnya sendiri.
mklement0
sumber
7

Mungkin tidak ada bawaan, tetapi Anda dapat menulis sendiri dengan mudah, seperti ini:

#!/bin/bash
echo -n "$1" > /tmp/tmpfile.$$
cat "$2" >> /tmp/tmpfile.$$
mv /tmp/tmpfile.$$ "$2"

Sesuatu seperti itu setidaknya ...

Rob I
sumber
6
1 untuk menggunakan $$ (PID saat ini) sebagai bagian dari nama file sementara. Jika membuat skrip untuk penggunaan umum, ini akan mencegah pengguna lain berpotensi menimpa file temp dengan menjalankan skrip yang sama pada waktu yang sama.
E Brown
3
Namun, penggunaan $$tidak cukup untuk kode produksi (serangan symlink google); tapi itu pasti lebih baik daripada nama file statis.
tripleee
1
cukup gunakanmktemp
mewa
7

Dalam beberapa keadaan, teks yang ditambahkan mungkin hanya tersedia dari stdin. Maka kombinasi ini akan bekerja.

echo "to be prepended" | cat - text.txt | tee text.txt

Jika Anda ingin menghilangkan teekeluaran, tambahkan > /dev/null.

sehari24jam
sumber
Saya sangat menyukai jawaban ini. Ini cara yang sangat bersih dan jelas untuk melakukannya. Penggunaan tee adalah solusi alami untuk masalah mencoba memasukkan output ke file input. Juga tidak ada peretasan dengan penggantian nama. Lebih baik daripada solusi pilihan tertinggi saat ini, karena tidak membuat file baru. Ini pada dasarnya yang paling dekat Anda akan mendapatkan >> untuk prapendemen daripada menambahkan.
DC2
Ini adalah jawaban terbaik dan terbersih.
nerdoc
6
Apakah ada jaminan bahwa teetidak akan memanjat text.txtsebelum catmembacanya? Saya kira tidak - yang akan membuat solusi ini berbahaya bagi kesehatan file.
Jonathan Leffler
3
@JonathanLeffler mungkin tidak. Saya mencoba kode ini untuk menguji: 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. Jika lenA1000000 (file 1Mb) dan lenB10000 (10Kb teks tambahan), maka file "a.txt" ditimpa dengan 20Kb huruf "b". Ini benar-benar rusak. Sekarang, jika Anda menggunakan 1Mb a.txt dan 1Mb teks untuk menambahkan, teemasuk ke loop menghasilkan file 7Gb +, saya harus menghentikan perintah. Jadi, jelas hasilnya tidak bisa ditebak untuk ukuran besar. Saya tidak memiliki informasi apakah itu harus berfungsi pada ukuran kecil.
VasiliNovikov
3
Sederhananya dalam istilah konseptual: Perintah ini akan mengakibatkan kehilangan data jika file input berukuran lebih besar dari ukuran buffer pipeline sistem Anda , yang biasanya 64 KB saat ini.
mklement0
7

Larutan:

printf '%s\n%s' 'text to prepend' "$(cat file.txt)" > file.txt

Perhatikan bahwa ini aman untuk semua jenis masukan, karena tidak ada perluasan. Misalnya, jika Anda ingin menambahkan !@#$%^&*()ugly text\n\t\n, itu hanya akan berfungsi:

printf '%s\n%s' '!@#$%^&*()ugly text\n\t\n' "$(cat file.txt)" > file.txt

Bagian terakhir yang tersisa untuk dipertimbangkan adalah penghapusan spasi di akhir file selama penggantian perintah "$(cat file.txt)". Semua solusi untuk ini relatif kompleks. Jika Anda ingin mempertahankan baris baru di akhir file.txt, lihat ini: https://stackoverflow.com/a/22607352/1091436

VasiliNovikov
sumber
Suka. Sangat portabel dan tidak perlu membuat file baru. Terima kasih!
pyb
1
Satu-satunya masalah dengan ini datang jika isi dari file.txtlebih besar dari yang dapat dimasukkan ke dalam daftar argumen printf.
Jonathan Leffler
6

Cara lain menggunakan sed:

sed -i.old '1 {i to be prepended
}' inFile

Jika garis yang akan ditambahkan multiline:

sed -i.old '1 {i\ 
to be prepended\
multiline
}' inFile
Mert Nuhoglu
sumber
Mengapa tidak sed -i '1ito be prepended' inFile- atau hanya diperbolehkan untuk GNU sed?
pengguna tidak diketahui
@userunknown: Secara standar sed, iperintah ini diikuti dengan garis miring terbalik dan baris baru, dan setiap baris masukan kecuali yang terakhir berakhir dengan garis miring terbalik juga. GNU sedmengizinkan singkatan di sepanjang baris yang Anda tanyakan, tetapi hanya GNU sedyang melakukannya. '
Jonathan Leffler
3

Seperti yang diuji di Bash (di Ubuntu), jika dimulai dengan file uji melalui;

echo "Original Line" > test_file.txt

Anda bisa mengeksekusi;

echo "$(echo "New Line"; cat test_file.txt)" > test_file.txt

atau, jika versi bash terlalu tua untuk $ (), Anda dapat menggunakan backticks;

echo "`echo "New Line"; cat test_file.txt`" > test_file.txt

dan menerima konten berikut dari "test_file.txt";

New Line
Original Line

Tidak ada file perantara, hanya bash / echo.

AlexanderESmith
sumber
2
jawaban terbaik, saya menulis satu baris ini untuk memutar file saya menggunakan jawaban ini: for i in $ (<file2.txt); lakukan echo "$ (echo $ i; cat file.txt)"> file.txt; selesai;
Aurangzeb
2

Solusi lain yang cukup mudah adalah:

    $ echo -e "string\n" $(cat file)
Menepuk
sumber
Ini berhasil untuk saya ... hanya sedikit modifikasi, untuk mempertahankan multilines dari file masukan Anda harus membungkusnya dalam tanda kutip jadi seperti ini: echo -e "string \ n" "$ (cat ~ / file.txt) "> ~ / file.txt;
Craig Wayne
2
Tidak adanya catperluasan parameter dalam tanda kutip ganda adalah alasan yang cukup bagus untuk downvote . Kode ini membagi konten file menjadi kata-kata, dan meneruskan setiap kata tersebut sebagai argumen terpisah ke echo. Anda kehilangan batas argumen asli, Anda kehilangan baris baru / tab / dll., Dan string seperti \tdan \ndalam teks asli diganti dengan tab dan baris baru alih-alih disimpan sebagaimana mestinya.
Charles Duffy
1

Jika Anda menyukai vi / vim, ini mungkin lebih sesuai gaya Anda.

printf '0i\n%s\n.\nwq\n' prepend-text | ed file
Ian Kelling
sumber
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
Jim
sumber
0

Saya akan merekomendasikan untuk mendefinisikan sebuah fungsi dan kemudian mengimpor dan menggunakannya jika diperlukan.

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
}

Kemudian gunakan seperti ini:

prepend_to_file test.txt "This is first"
prepend_to_file test.txt "This is second"

Konten file Anda kemudian akan menjadi:

This is second
This is first

Saya akan menggunakan pendekatan ini untuk mengimplementasikan pembaru log perubahan.

AwesomeBobX64
sumber