:adalah nama lain untuk true. Keduanya builtin shell dalam bash, tetapi tidak ada /bin/:, hanya a /bin/true. Pengalihan output menyebabkan shell ke open(2)file dengan O_CREAT|O_TRUNC. Jika tidak ada yang tertulis, panjangnya nol.
Menyatukan kedua potongan itu, :> fileadalah idiom yang cukup umum untuk memotong file. Namun, kebanyakan orang akan berusaha membuatnya tidak terlihat aneh dengan menulis : >file.
Karena Anda bertanya dalam komentar tentang baris ke-2, saya akan mengubah komentar saya menjadi jawaban. (Meskipun Anda tidak menanyakan hal ini dalam pertanyaan Anda.)
Baris ke-2 adalah loop yang membaca baris dari otherfileke beberapa variabel bernama. Badan loop digunakan echountuk mencetaknya dengan ;pemisah, bukan spasi putih apa pun yang mereka miliki sebelumnya. fileditutup dan dibuka kembali (untuk ditambahkan) setiap iterasi, karena redirect ada di dalam loop. Menggunakan while ...;do read -r ...;done <otherfile >fileakan menyedot lebih sedikit, dan menghindari kebutuhan untuk memotong file terlebih dahulu. read -rtidak makan \sebagai karakter pelarian.
Pemrosesan teks dalam bash cukup lambat. Bagian yang tidak dapat dihindari: readharus berjalan satu byte pada satu waktu (satu read(2)system call per byte) untuk menghindari overshooting ujung baris. Akan lebih baik menggunakan alat yang tepat untuk pekerjaan itu:
awk -vOFS=';' '{ print $1, $2, $4, $5, $3 }' -- otherfile >file
--berarti skrip Anda tidak rusak jika otherfiledinamai sesuatu yang konyol --version.
Mengatur Pemisah Bidang Output ke ;berarti Anda bisa melewati beberapa bidang sebagai argumen untuk dicetak. Shell readmenetapkan seluruh sisa baris dengan spasi putih ke variabel terakhir, tetapi tidak ada cara untuk mengatakan awk untuk hanya dibagi menjadi 5. Jika itu penting, mungkin terus menggunakan bash loop, karena itu merepotkan dalam awk. Perl membuatnya mudah, karena ini splitbisa menggunakan argumen max-field, tapi jauh lebih lambat untuk memulai daripada awk.
Sebenarnya, ternyata tidak terlalu sulit, hanya sebuah regex jelek untuk ditulis. Untuk mendapatkan rest-of-the-line dan bukan $5di awk, pengalihan bidang masih kehilangan spasi asli mereka. Ide layak pertama saya adalah dengan menggunakan gensubdi $0(seluruh baris) untuk menghapus pertama 4 bidang (yaitu non-ruang diikuti dengan spasi), meninggalkan segala sesuatu yang lain:
awk -vOFS=';' '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1); print $1, $2, $4, tail, $3 }' -- otherfile >file
Saya melakukannya dengan benar pada percobaan pertama, tetapi fakta bahwa saya terkesan dengan diri saya sendiri karena mengatakan sesuatu tentang keterbacaan kode awk itu. >. <
Perhatikan bagaimana ini sama printseperti sebelumnya, tetapi dengan taildi tempat $5.
echo 'A B c DD e f g f' |
awk -vOFS=\; '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1);
print $1, $2, $4, tail, $3 }'
A;B;DD;e f g f;c
Ini akan lebih mengesankan jika saya bisa menyalin / menempelkan literal dan menunjukkan bahwa ia muncul di output. Ketik satu di bash dengan ^ Q. ctrl-Q berarti Mengutip penekanan tombol berikutnya sebagai karakter literal, karena pengeditan garis gaya emacs bash sama dengan emacs aktual untuk ini.
http://mywiki.wooledge.org/BashFAQ memiliki beberapa hal bermanfaat tentang penulisan skrip dengan cara yang tidak akan merusak data atau nama file apa pun yang Anda masukkan ke dalam skrip.
:>bukan operator tunggal. Mungkin lebih mudah untuk dipahami jika Anda membacanya sebagai: > filegantinya.