:
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, :> file
adalah 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 otherfile
ke beberapa variabel bernama. Badan loop digunakan echo
untuk mencetaknya dengan ;
pemisah, bukan spasi putih apa pun yang mereka miliki sebelumnya. file
ditutup dan dibuka kembali (untuk ditambahkan) setiap iterasi, karena redirect ada di dalam loop. Menggunakan while ...;do read -r ...;done <otherfile >file
akan menyedot lebih sedikit, dan menghindari kebutuhan untuk memotong file terlebih dahulu. read -r
tidak makan \
sebagai karakter pelarian.
Pemrosesan teks dalam bash cukup lambat. Bagian yang tidak dapat dihindari: read
harus 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 otherfile
dinamai sesuatu yang konyol --version
.
Mengatur Pemisah Bidang Output ke ;
berarti Anda bisa melewati beberapa bidang sebagai argumen untuk dicetak. Shell read
menetapkan 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 split
bisa 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 $5
di awk, pengalihan bidang masih kehilangan spasi asli mereka. Ide layak pertama saya adalah dengan menggunakan gensub
di $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 print
seperti sebelumnya, tetapi dengan tail
di 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: > file
gantinya.