Apa arti simbol aneh ini “:>” dalam bash

47

Saya menemukan sesuatu dalam naskah, tetapi bukan milik naskah utama. Ada :>dalam barisan.

Bisakah Anda menjelaskan kepada saya apa artinya?

:> file
while read A B C D E; do echo "$A;$B;$D;$E;$C" >> file; done < otherfile
diego9403
sumber
6
Yang penting, :>bukan operator tunggal. Mungkin lebih mudah untuk dipahami jika Anda membacanya sebagai : > filegantinya.
jpfx1342
Ini berarti bahwa orang yang menulis script harus diarahkan output dari loop ke file: while read A B C D E; do echo "$A;$B;$D;$E;$C"; done < otherfile > file. Atau lebih baik lagi, mereka seharusnya menggunakan alat yang tepat untuk pekerjaan itu, awk, seperti yang disarankan oleh Peter . Selain itu, Anda hampir selalu ingin menggunakan -rsakelarread .
Tom Fenech
Di luar bash, itu akan menjadi senyuman bagi seekor gagak.
smci

Jawaban:

46

Ada:> dalam baris skrip bash. Apa artinya?

:> file

Ini adalah cara pintas untuk mengatakan:

  • Jika filetidak ada maka buat yang lain memotongnya menjadi 0byte.

Ini berarti Anda dapat yakin bahwa itu fileada dan kosong.

Anda juga dapat menggunakan > filetetapi :> filelebih portabel.

Lihat pertanyaan Stack Overflow Apa Tujuan dari ':' (titik dua) GNU Bash Builtin? untuk informasi lebih lanjut.

DavidPostill
sumber
Saya tidak mengerti baris kedua. Saya pikir, itu membaca variabel baca. Perintah gema juga aneh. Bisakah Anda jelaskan?
diego9403
Saya bukan ahli Unix tapi saya pikir baris kedua membaca hal-hal dari otherfiledan ke echomereka file. Itu juga membuat variabel dari apa pun yang dibacanya ... Jika Anda ingin jawaban yang pasti silakan ajukan pertanyaan Anda sendiri.
DavidPostill
2
@ diego9403: readmendapat masukan dari stdin. Dengan sendirinya, itu akan membaca apa yang Anda ketik. Karena stdin telah dialihkan ke <otherfilemaka isi otherfile"diketik" ke dalam stdin. Jadi readdapatkan nilai-nilai baris demi baris ke dalam variabel $ A, $ B, $ C, $ D dan $ E.
slebetman
Jadi itu hanya alternatif yang lebih tidak jelas truncatedari dari coreutils?
Federico Poloni
1
@PeterCordes saya tidak bermaksud "tidak jelas" seperti pada "tidak biasa", tetapi seperti "kurang jelas bagi pembaca".
Federico Poloni
29

Sepertinya cara mewah untuk membuat file baru. In bash :adalah perintah nol:

$ type : 
: is a shell builtin 
$ help : 
:: :
    Null command.

    No effect; the command does nothing.

    Exit Status:
    Always succeeds.

>mengalihkan output :ke file.

Arkadiusz Drabczyk
sumber
2
Ini juga akan memotong file jika sudah ada ...
DavidPostill
2
ya, inilah yang >dilakukannya
Arkadiusz Drabczyk
2
:adalah singkatan true. Mungkin di dalam beberapa shell, truebukan builtin? Keduanya built-in di bash.
Peter Cordes
12

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

Peter Cordes
sumber