Bagaimana cara menambahkan teks ke awal file di Bash?

285

Hai, saya ingin menambahkan teks ke file. Misalnya saya ingin menambahkan tugas ke awal file todo.txt. Saya sadar echo 'task goes here' >> todo.txttetapi itu menambahkan baris ke akhir file (bukan yang saya inginkan).

pengguna479534
sumber
2
Di sana jika tidak ada cara yang efisien untuk melakukan itu untuk file besar: unix.stackexchange.com/questions/87772/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
@bisakah Anda melihat metode ini superuser.com/a/1352628/11116
Evan Carroll

Jawaban:

374
echo 'task goes here' | cat - todo.txt > temp && mv temp todo.txt

atau

sed -i '1s/^/task goes here\n/' todo.txt

atau

sed -i '1itask goes here' todo.txt
Dennis Williamson
sumber
4
yang pertama berhasil! maukah Anda menjelaskan logika? im tidak terlalu yakin bagaimana menafsirkan sintaks.
user479534
44
@ user8347: Pipa ( |) pesan ( echo '...') catyang menggunakan -(input standar) sebagai file pertama dan todo.txtsebagai yang kedua. catbuat beberapa file. Kirim output ( >) ke file bernama temp. Jika tidak ada kesalahan ( &&) sejak catsaat itu ganti nama ( mv) tempfile kembali ke file asli ( todo.txt).
Dennis Williamson
1
@itaifrenkel: Saya harus melihat apa yang Anda lakukan, tetapi jika catmenerima backslash n literal, itu tidak akan mengubahnya menjadi baris baru. Sesuatu yang lain pasti telah melakukan itu. Alih-alih cat, coba pilih hexdump -Capakah Anda benar-benar mengirim backslash dan n atau apakah itu baris baru. Anda juga dapat mencoba cat -emenampilkan akhiran garis.
Dennis Williamson
1
Menggunakan 2 dan 3 (3 tampaknya lebih mudah bagi saya) memungkinkan Anda untuk menambahkan teks ke banyak file sekaligus.
Felix
4
@ Kirira: Cara 1melakukan perintah berikutnya hanya pada baris satu file dan iperintahnya adalah menyisipkan. Lihat di halaman manual di bawah bagian "Alamat" dan di bagian "Perintah nol atau satu alamat".
Dennis Williamson
73

Pilihan yang lebih sederhana menurut saya adalah:

echo -e "task goes here\n$(cat todo.txt)" > todo.txt

Ini berfungsi karena perintah di dalam $(...)dieksekusi sebelum todo.txtditimpa dengan> todo.txt

Sementara jawaban lain berfungsi dengan baik, saya menemukan ini jauh lebih mudah diingat karena saya menggunakan gema dan kucing setiap hari.

EDIT: Solusi ini adalah ide yang sangat buruk jika ada backslash todo.txt, karena berkat -eflag echo akan menafsirkannya. Cara lain yang jauh lebih mudah untuk memasukkan baris baru ke dalam kata pengantar adalah ...

echo "task goes here
$(cat todo.txt)" > todo.txt

... cukup menggunakan baris baru. Tentu, itu bukan satu-liner lagi, tetapi secara realistis itu bukan satu-liner sebelumnya, juga. Jika Anda melakukan ini di dalam skrip, dan khawatir tentang indentasi (misalnya Anda menjalankan ini di dalam suatu fungsi) ada beberapa solusi untuk membuat ini tetap pas, termasuk tetapi tidak terbatas pada:

(echo 'task goes here' && cat todo.txt) > todo.txt
echo 'task goes here'$'\n'"$(cat todo.txt)" > todo.txt

Juga, jika Anda peduli apakah baris baru akan ditambahkan ke akhir todo.txt, jangan gunakan ini. Ya, kecuali yang kedua ke terakhir. Itu tidak mengacaukan akhirnya.

John Alberts
sumber
1
Saya tidak mendapatkan $ (...) dieksekusi sama sekali.
SCL
2
Itu mungkin bekerja lebih baik (atau sama sekali) dengan tanda kutip ganda daripada tunggal ...
ℝaphink
5
Tidakkah -ejuga mengonversi urutan pelarian di dalam todo.txt?
mk12
2
Workarounds yield -> cat: <destination filename>: file input adalah file output ...
ingyhere
printf akan jauh lebih konsisten di seluruh platform dan umumnya harus bekerja lebih lancar daripada echo -e
Peter Berg
28

The moreutilsmemiliki alat yang bagus disebut sponge:

echo "task goes here" | cat - todo.txt | sponge todo.txt

Ini akan "menyerap" STDIN dan kemudian menulis ke file, yang berarti Anda tidak perlu khawatir tentang file sementara dan memindahkannya.

Anda dapat moreutilsmenggunakan banyak distro Linux, melalui apt-get install moreutils, atau pada OS X menggunakan Homebrew , dengan brew install moreutils.

slhck
sumber
Saya akan pergi untuk (echo 'ble'; cat todo.txt):-)
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
11

Anda dapat menggunakan Vim dalam mode Ex:

ex -s -c '1i|task goes here' -c x todo.txt
  1. 1 pilih baris pertama

  2. i memasukkan

  3. x Simpan dan tutup

Steven Penny
sumber
5

Anda dapat membuat file sementara yang baru.

echo "new task" > new_todo.txt
cat todo.txt >> new_todo.txt
rm todo.txt
mv new_todo.txt todo.txt

Anda mungkin juga menggunakan sedatau awk. Tetapi pada dasarnya hal yang sama terjadi.

Keith
sumber
1
Katakanlah Anda kehabisan ruang disk sehingga new_todo.txthanya ditulis sebagian. Solusi Anda tampaknya kehilangan file asli.
NPE
Siapa yang kehabisan ruang disk? ;-) Ini hanya contoh sederhana.
Keith
2
@Keith Seseorang yang bekerja pada VM yang tidak berharap membutuhkan drive virtual yang sangat besar. Atau seseorang memindahkan file besar. Dalam kasus apa pun, argumen sebenarnya yang menentang hal ini adalah izin direktori; jika Anda tidak memiliki izin untuk membuat file baru di direktori yang diberikan, satu-satunya perintah yang akan berhasil dijalankan dalam skrip Anda adalah rmdari file asli.
Parthian Shot
3

Jika file teks cukup kecil untuk muat dalam memori, Anda tidak perlu membuat file sementara untuk menggantinya. Anda dapat memuat semuanya ke dalam memori dan menuliskannya kembali ke file.

echo "$(echo 'task goes here' | cat - todo.txt)" > todo.txt

Tidak mungkin menambahkan baris ke awal file tanpa harus menulis seluruh file.

Rucent88
sumber
Hanya untuk mengajukan pertanyaan yang jelas: Di mana batas karakter variabel shell?
nixda
Sejauh yang saya ketahui, itu hanya dibatasi oleh jumlah memori yang tersedia. Saya telah mengisi variabel lebih dari 100MB ke dalam memori. text=$(cat file). Berhati-hatilah untuk hanya menggunakan teks, karena variabel shell bukan biner bersih mywiki.wooledge.org/BashFAQ/058
Rucent88
2

Anda tidak dapat menyisipkan konten di awal file. Satu-satunya hal yang dapat Anda lakukan adalah mengganti konten yang ada atau menambahkan byte setelah akhir file saat ini.

Solusi apa pun untuk pertanyaan Anda kemudian membutuhkan file sementara (atau buffer) yang akan dibuat (pada memori atau pada disk) yang pada akhirnya akan menimpa file asli.

Waspadalah jangan sampai kehilangan data dengan menyimpan file asli saat membuat yang baru, jika sistem file terjadi penuh selama proses. misalnya:

cat <(echo task go there) todo.txt > todo.txt.new && mv todo.txt.new todo.txt
Jlliagre
sumber
Para downvoters dipersilakan untuk menjelaskan motivasi mereka. Tidak ada jawaban yang tersisa, termasuk yang diterima, yang bertentangan dengan jawaban saya.
jlliagre
Ini sulit untuk diurai karena <...> terlihat seperti tanda kurung, yang saya asumsikan tidak. Ruang antara <dan (mungkin bisa membantu?
dumbledad
Ini tidak bekerja untuk saya. echo HOME=\"/g/Users/timregan/\" | cat - 'F:\Program Files\Git\etc\profile'berfungsi tetapi cat <echo HOME=\"/g/Users/timregan/\" 'F:\Program Files\Git\etc\profile'memberikan kesalahan "gema: Tidak ada file atau direktori"
dumbledad
@dumbledad Anda terlalu memikirkan balasan saya. Tidak ada yang bisa Anda uraikan. Ruang antara <dan (akan memecah sintaks. Cobacat <(echo HOME=\"/g/Users/timregan/\") 'F:\Program Files\Git\etc\profile'
jlliagre
1

Anda bisa menggunakan tee:

echo 'task goes here' | cat - todo.txt | tee todo.txt
Radu Rădeanu
sumber
3
Tidak, Anda tidak dapat memintaubuntu.com/a/752451
Steven Penny
0

GitBash + Windows10 + Multline :

Ini adalah versi yang memungkinkan Anda menggunakan string multi-line .

##############################################
## This section for demo purpose only,      ##
## So you can save entire file as           ##
## whatever.sh and run it.                  ##
##                                          ##
##############################################
> MY_TARGET_FILE.txt ##Make Or Clear File
echo "[STARTER_CONTENT]" >> MY_TARGET_FILE.txt
##############################################

## Below is main code:

##################################################
TARGET_FILE_VARIABLE="MY_TARGET_FILE.txt"
ADD_TO_HEAD_VARIABLE=$(cat << "HEREDOC_HEAD_TEXT"
//|  +-------------------------------------+   |//
//|  |                                     |   |//
//|  |     MESSAGE_FOR_HEAD_OF_FILE        |   |//
//|  |                                     |   |//
//|  +-------------------------------------+   |//
HEREDOC_HEAD_TEXT
)
##################################################
TAR=$TARGET_FILE_VARIABLE                       ##
TEX=$ADD_TO_HEAD_VARIABLE                       ##
echo "$TEX" | cat - $TAR > TEMP && mv TEMP $TAR ##
##################################################

## Expected contents of MY_TARGET_FILE.txt :
## //|  +-------------------------------------+   |//
## //|  |                                     |   |//
## //|  |     MESSAGE_FOR_HEAD_OF_FILE        |   |//
## //|  |                                     |   |//
## //|  +-------------------------------------+   |//
## [STARTER_CONTENT]
J MADISON
sumber