GNU/Linux >> Belajar Linux >  >> Linux

7 Penggunaan Perintah Tempel yang Esensial dan Praktis di Linux

Pada artikel sebelumnya, kita telah membahas tentang perintah cut yang dapat digunakan untuk mengekstrak kolom dari file data teks CSV atau tabular.

paste perintah melakukan kebalikannya:menggabungkan beberapa file input untuk menghasilkan file teks baru yang dibatasi dari mereka. Kita akan melihat cara efektif menggunakan perintah Tempel di Linux dan Unix.

7 Contoh praktis perintah Tempel di Linux

Jika Anda lebih suka video, Anda dapat menonton video ini menjelaskan contoh perintah Tempel yang sama yang dibahas dalam artikel ini.

1. Menempelkan kolom

Dalam kasus penggunaan paling dasar, paste perintah mengambil N masukan file dan gabungkan baris demi baris pada output:

sh$ printf "%s\n" {a..e} | tee letters
a
b
c
d
e

sh$ printf "%s\n" {1..5} | tee digits
1
2
3
4
5

sh$ paste letters digits
a    1
b    2
c    3
d    4
e    5

Tapi mari kita tinggalkan sekarang penjelasan teoretis untuk mengerjakan contoh praktis. Jika Anda telah mengunduh file sampel yang digunakan dalam video di atas, Anda dapat melihat saya memiliki beberapa file data yang sesuai dengan berbagai kolom dari sebuah tabel:

sh$ head -3 *.csv
==> ACCOUNTLIB.csv <==
ACCOUNTLIB
TIDE SCHEDULE
VAT BS/ENC

==> ACCOUNTNUM.csv <==
ACCOUNTNUM
623477
445452

==> CREDIT.csv <==
CREDIT
<--- empty line
<--- empty line

==> DEBIT.csv <==
DEBIT
00000001615,00
00000000323,00

Cukup mudah untuk menghasilkan file teks tab-delimited dari data tersebut:

sh$ paste *.csv | head -3
ACCOUNTLIB    ACCOUNTNUM    CREDIT    DEBIT
TIDE SCHEDULE    623477        00000001615,00
VAT BS/ENC    445452        00000000323,00

Seperti yang Anda lihat, saat ditampilkan di konsol, konten file nilai yang dipisahkan tab tersebut tidak menghasilkan tabel yang diformat dengan sempurna. Tapi ini adalah desain:paste perintah tidak digunakan untuk membuat file teks dengan lebar tetap, tetapi hanya file teks yang dibatasi di mana satu karakter tertentu ditetapkan sebagai pemisah bidang.

Jadi, meskipun tidak jelas pada output di atas, sebenarnya ada satu dan hanya satu karakter tab di antara setiap bidang. Mari kita nyatakan dengan menggunakan perintah sed:

sh$ paste *.csv | head -3 | sed -n l
ACCOUNTLIB\tACCOUNTNUM\tCREDIT\tDEBIT$
TIDE SCHEDULE\t623477\t\t00000001615,00$
VAT BS/ENC\t445452\t\t00000000323,00$

Sekarang, karakter yang tidak terlihat ditampilkan dengan jelas di output. Dan Anda dapat melihat karakter tab ditampilkan sebagai \t . Anda dapat menghitungnya:selalu ada tiga tab di setiap jalur keluaran— satu di antara setiap bidang. Dan ketika Anda melihat dua dari mereka berturut-turut, itu hanya berarti ada bidang kosong di sana. Ini sering terjadi pada file contoh khusus saya karena pada setiap baris, bidang KREDIT atau DEBIT disetel, tetapi tidak pernah keduanya secara bersamaan.

2. Mengubah pembatas bidang

Seperti yang telah kita lihat, paste perintah menggunakan karakter tab sebagai pemisah bidang default ("pembatas"). Sesuatu yang dapat kita ubah menggunakan -d pilihan. Katakanlah saya ingin menggunakan titik koma sebagai gantinya:

# The quotes around the ';' are used to prevent the
# shell to consider that semi-colon as being a command separator
sh$ paste -d ';' *.csv | head -3
ACCOUNTLIB;ACCOUNTNUM;CREDIT;DEBIT
TIDE SCHEDULE;623477;;00000001615,00
VAT BS/ENC;445452;;00000000323,00

Tidak perlu menambahkan sed perintah di akhir pipa di sini karena pemisah yang kami gunakan adalah karakter yang dapat dicetak. Bagaimanapun, hasilnya sama:pada baris tertentu, setiap bidang dipisahkan dari tetangganya dengan menggunakan pembatas satu karakter.

3. Memindahkan data menggunakan mode serial

Contoh di atas memiliki satu kesamaan:paste perintah membaca semua file inputnya secara paralel, sesuatu yang diperlukan agar dapat menggabungkannya secara baris demi baris dalam output.

Tapi paste perintah juga dapat beroperasi dalam apa yang disebut mode serial , diaktifkan menggunakan -s bendera. Seperti namanya, dalam mode serial, paste perintah akan membaca file input satu demi satu. Isi dari file input pertama akan digunakan untuk menghasilkan baris output pertama. Kemudian isi dari file input kedua akan digunakan untuk menghasilkan baris output kedua, dan seterusnya. Itu juga berarti output akan memiliki baris sebanyak file yang ada di input.

Secara lebih formal, data diambil dari file N akan muncul sebagai N baris th dalam output dalam mode serial, sedangkan itu akan muncul sebagai N kolom th dalam mode "paralel" default. Dalam istilah matematika, tabel yang diperoleh dalam mode serial adalah transpos tabel yang dihasilkan dalam mode default (dan sebaliknya ).

Untuk mengilustrasikannya, mari pertimbangkan subsampel kecil dari data kita:

sh$ head -5 ACCOUNTLIB.csv | tee ACCOUNTLIB.sample
ACCOUNTLIB
TIDE SCHEDULE
VAT BS/ENC
PAYABLES
ACCOMMODATION GUIDE
sh$ head -5 ACCOUNTNUM.csv | tee ACCOUNTNUM.sample
ACCOUNTNUM
623477
445452
4356
623372

Dalam mode default ("paralel"), data file input akan berfungsi sebagai kolom dalam output, menghasilkan tabel dua kolom dengan lima baris:

sh$ paste *.sample
ACCOUNTLIB    ACCOUNTNUM
TIDE SCHEDULE    623477
VAT BS/ENC    445452
PAYABLES    4356
ACCOMMODATION GUIDE    623372

Tetapi dalam mode serial, data file input akan muncul sebagai baris, sekarang menghasilkan tabel lima kolom dengan dua baris:

sh$ paste -s *.sample
ACCOUNTLIB    TIDE SCHEDULE    VAT BS/ENC    PAYABLES    ACCOMMODATION GUIDE
ACCOUNTNUM    623477    445452    4356    623372

4. Bekerja dengan masukan standar

Seperti banyak utilitas standar, paste perintah dapat menggunakan input standar untuk membaca data. Baik secara implisit ketika tidak ada nama file yang diberikan sebagai argumen, atau secara eksplisit dengan menggunakan - . khusus nama file. Ternyata, ini tidak terlalu berguna:

# Here, the paste command is useless
head -5 ACCOUNTLIB.csv | paste
ACCOUNTLIB
TIDE SCHEDULE
VAT BS/ENC
PAYABLES
ACCOMMODATION GUIDE

Saya mendorong Anda untuk mengujinya sendiri, tetapi sintaks berikut akan menghasilkan hasil yang sama— membuat sekali lagi perintah tempel tidak berguna dalam kasus itu:

head -5 ACCOUNTLIB.csv | paste -

Jadi, apa gunanya membaca data dari input standar? Nah, dengan -s bendera, segalanya menjadi jauh lebih menarik seperti yang akan kita lihat sekarang.

4.1. Menggabungkan baris file

Seperti yang telah kita lihat beberapa paragraf sebelumnya, dalam mode serial perintah tempel akan menulis semua baris file input pada baris output yang sama. Ini memberi kita cara sederhana untuk menggabungkan semua baris yang dibaca dari input standar menjadi hanya satu (berpotensi sangat panjang) baris output:

sh$ head -5 ACCOUNTLIB.csv | paste -s -d':'
ACCOUNTLIB:TIDE SCHEDULE:VAT BS/ENC:PAYABLES:ACCOMMODATION GUIDE

Ini sebagian besar adalah hal yang sama yang dapat Anda lakukan menggunakan tr perintah, tetapi dengan satu perbedaan sekalipun. Mari kita gunakan diff utilitas untuk mengetahui bahwa:

sh$ diff <(head -5 ACCOUNTLIB.csv | paste -s -d':') \
         <(head -5 ACCOUNTLIB.csv | tr '\n' ':')
1c1
< ACCOUNTLIB:TIDE SCHEDULE:VAT BS/ENC:PAYABLES:ACCOMMODATION GUIDE
---
> ACCOUNTLIB:TIDE SCHEDULE:VAT BS/ENC:PAYABLES:ACCOMMODATION GUIDE:
\ No newline at end of file

Seperti yang dilaporkan oleh diff utilitas, kita dapat melihat tr perintah telah menggantikan setiap contoh karakter baris baru dengan pembatas yang diberikan, termasuk yang terakhir. Di sisi lain, paste perintah membuat karakter baris baru terakhir tidak tersentuh. Jadi tergantung apakah Anda memerlukan pembatas setelah kolom terakhir atau tidak, Anda akan menggunakan satu perintah atau yang lain.

4.2. Pemformatan multi-kolom dari satu file input

Menurut spesifikasi Grup Terbuka, “masukan standar harus dibaca satu baris setiap kali” dengan paste memerintah. Jadi, melewati beberapa kemunculan - nama file khusus sebagai argumen untuk paste perintah akan menghasilkan banyak baris input yang berurutan ditulis ke dalam baris output yang sama:

sh$ seq 9 | paste - - -
1    2    3
4    5    6
7    8    9

Untuk memperjelas, saya mendorong Anda untuk mempelajari perbedaan antara dua perintah di bawah ini. Dalam kasus pertama, perintah tempel membuka tiga kali file yang sama, menghasilkan duplikasi data dalam output. Di sisi lain, dalam kasus kedua, file ACCOUNTLIB dibuka hanya sekali (oleh shell), tetapi dibaca tiga kali untuk setiap baris (dengan paste perintah), sehingga konten file ditampilkan sebagai tiga kolom:

sh$ paste ACCOUNTLIB.csv ACCOUNTLIB.csv ACCOUNTLIB.csv | head -2
ACCOUNTLIB    ACCOUNTLIB    ACCOUNTLIB
TIDE SCHEDULE    TIDE SCHEDULE    TIDE SCHEDULE

sh$ paste - - - < ACCOUNTLIB.csv | head -2
ACCOUNTLIB    TIDE SCHEDULE    VAT BS/ENC
PAYABLES    ACCOMMODATION GUIDE    VAT BS/ENC

Mengingat perilaku paste perintah ketika membaca dari input standar, biasanya tidak disarankan untuk menggunakan beberapa - nama file khusus dalam mode serial. Dalam hal ini, kemunculan pertama akan membaca input standar hingga akhir, dan kemunculan berikutnya dari - akan membaca dari aliran input yang sudah habis— sehingga tidak ada lagi data yang tersedia:

# The following command will produce 3 lines of output.
# But the first one exhausted the standard input,
# so the remaining two lines are empty
sh$ seq 9 | paste -s - - -
1    2    3    4    5    6    7    8    9

5. Bekerja dengan file dengan panjang berbeda

Spesifikasi Open Group untuk paste utilitas cukup jelas:

Jika kondisi akhir file terdeteksi pada satu atau lebih file input, tetapi tidak semua file input, tempel akan berperilaku seolah-olah baris kosong dibaca dari file di mana akhir file terdeteksi, kecuali jika -s opsi ditentukan.

Jadi, perilakunya adalah apa yang Anda harapkan:data yang hilang digantikan oleh konten "kosong". Untuk mengilustrasikan perilaku itu, mari kita catat beberapa transaksi lagi ke dalam "database" kita. Untuk menjaga file asli tetap utuh, kami akan mengerjakan salinan data kami:

# Copy files
sh$ for f in ACCOUNTNUM ACCOUNTLIB CREDIT DEBIT; do
  cp ${f}.csv NEW${f}.csv
done

# Update the copy
sh$ cat - << EOF >> NEWACCOUNTNUM.csv
1080
4356
EOF

sh$ cat - << EOF >> NEWDEBIT.csv
00000001207,35

EOF

sh$ cat - << EOF >> NEWCREDIT.csv

00000001207,35
EOF

Dengan pembaruan tersebut, kami sekarang telah mendaftarkan perpindahan modal baru dari akun #1080 ke akun #4356. Namun, seperti yang mungkin Anda perhatikan, saya tidak repot-repot memperbarui file ACCOUNTLIB. Ini sepertinya bukan masalah besar karena paste perintah akan mengganti baris yang hilang dengan data kosong:

sh$ paste -d';' NEWACCOUNTNUM.csv \
                NEWACCOUNTLIB.csv \
                NEWDEBIT.csv \
                NEWCREDIT.csv | tail
4356;PAYABLES;;00000000402,03
613866;RENTAL COSTS;00000000018,00;
4356;PAYABLES;;00000000018,00
657991;MISCELLANEOUS CHARGES;00000000015,00;
445333;VAT BS/DEBIT;00000000003,00;
4356;PAYABLES;;00000000018,00
626510;LANDLINE TELEPHONE;00000000069,14;
445452;VAT BS/ENC;00000000013,83;
1080;;00000001207,35; # <-- the account label is missing here
4356;;;00000001207,35 # <-- the account label is missing here

Tapi hati-hati, paste perintah hanya dapat mencocokkan baris dengan fisik position:yang bisa dilihatnya hanyalah sebuah file "lebih pendek" dari yang lain. Bukan di mana datanya hilang. Jadi selalu menambahkan bidang kosong di akhir output, sesuatu yang dapat menyebabkan offset tak terduga dalam data Anda. Mari kita perjelas dengan menambahkan transaksi lain:

sh$ cat << EOF >> NEWACCOUNTNUM.csv
4356
3465
EOF

sh$ cat << EOF >> NEWACCOUNTLIB.csv
PAYABLES
WEB HOSTING
EOF

sh$ cat << EOF >> NEWDEBIT.csv

00000000706,48
EOF

sh$ cat << EOF >> NEWCREDIT.csv
00000000706,48

EOF

Kali ini, saya lebih teliti karena saya memperbarui nomor rekening (ACCOUNTNUM) dengan benar, dan label yang sesuai (ACCOUNTLIB) serta file data KREDIT dan DEBIT. Tapi karena ada data yang hilang di record sebelumnya, paste perintah tidak lagi dapat menyimpan bidang terkait pada baris yang sama:

sh$ paste -d';' NEWACCOUNTNUM.csv \
                NEWACCOUNTLIB.csv \
                NEWDEBIT.csv \
                NEWCREDIT.csv | tail
4356;PAYABLES;;00000000018,00
657991;MISCELLANEOUS CHARGES;00000000015,00;
445333;VAT BS/DEBIT;00000000003,00;
4356;PAYABLES;;00000000018,00
626510;LANDLINE TELEPHONE;00000000069,14;
445452;VAT BS/ENC;00000000013,83;
1080;PAYABLES;00000001207,35;
4356;WEB HOSTING;;00000001207,35
4356;;;00000000706,48
3465;;00000000706,48;

Seperti yang Anda lihat, akun #4356 dilaporkan dengan label “WEB HOSTING” padahal, pada kenyataannya, yang terakhir akan muncul di baris yang sesuai dengan akun #3465.

Sebagai kesimpulan, jika Anda harus berurusan dengan data yang hilang, alih-alih paste perintah yang harus Anda pertimbangkan untuk menggunakan join utilitas karena yang terakhir akan cocok dengan baris berdasarkan kontennya, dan bukan berdasarkan posisi yang ada di file input. Itu membuatnya jauh lebih cocok untuk aplikasi gaya "database". Saya sudah memublikasikan video tentang join perintah, tapi itu mungkin pantas mendapatkan artikelnya sendiri, jadi beri tahu kami jika Anda tertarik dengan topik itu!

6. Bersepeda melewati pembatas

Dalam sebagian besar kasus penggunaan, Anda hanya akan memberikan satu karakter sebagai pembatas. Inilah yang kami lakukan sampai sekarang. Namun, jika Anda memberikan beberapa karakter setelah -d opsi, perintah tempel akan menggilirnya:karakter pertama akan digunakan sebagai pembatas kolom pertama pada baris, karakter kedua sebagai pembatas kolom kedua, dan seterusnya.

sh$ paste -d':+-' ACCOUNT*.csv CREDIT.csv DEBIT.csv | head -5
ACCOUNTLIB:ACCOUNT NUM+CREDIT-DEBIT
TIDE SCHEDULE:623477+-00000001615,00
VAT BS/ENC:445452+-00000000323,00
PAYABLES:4356+00000001938,00-
ACCOMODATION GUIDE:623372+-00000001333,00

Pembatas bidang hanya dapat muncul antara bidang. Tidak di akhir baris. Dan Anda tidak dapat menyisipkan lebih dari satu pembatas di antara dua bidang yang diberikan. Sebagai trik untuk mengatasi keterbatasan ini, Anda dapat menggunakan /dev/null file khusus sebagai input tambahan di mana Anda memerlukan pemisah tambahan:

# Display the opening bracket between the
# ACCOUNTLIB field and the ACCOUNTNUM field, and
# the closing bracket between the ACCOUNTNUM field
# and the empty `/dev/null` field:
sh$ paste  -d'()' \
           ACCOUNT*.csv /dev/null | head -5
ACCOUNTLIB(ACCOUNTNUM)
TIDE SCHEDULE(623477)
VAT BS/ENC(445452)
PAYABLES(4356)
ACCOMODATION GUIDE(623372)

Sesuatu yang Anda bahkan mungkin menyalahgunakan:

sh$ paste -d'# is ' \
          - ACCOUNTNUM.csv - - - ACCOUNTLIB.csv < /dev/null | tail -5
#657991 is MISCELLANEOUS CHARGES
#445333 is VAT BS/DEBIT
#4356 is PAYABLES
#626510 is LANDLINE TELEPHONE
#445452 is VAT BS/ENC

Namun, tidak perlu dikatakan, jika Anda mencapai tingkat kerumitan itu, itu mungkin petunjuk paste utilitas belum tentu merupakan alat terbaik untuk pekerjaan itu. Mungkin layak dipertimbangkan, dalam hal ini, sesuatu yang lain seperti sed atau perintah awk.

Tetapi bagaimana jika daftar berisi pembatas lebih sedikit dari yang dibutuhkan untuk menampilkan baris dalam output? Menariknya, paste perintah akan "berputar" di atasnya. Jadi, setelah daftar habis, paste perintah akan melompat kembali ke pembatas pertama, sesuatu yang mungkin membuka pintu untuk beberapa penggunaan kreatif. Bagi saya sendiri, saya tidak dapat membuat sesuatu yang benar-benar berguna dengan fitur yang diberikan data saya. Jadi, Anda harus puas dengan contoh yang agak mengada-ada berikut ini. Tapi itu tidak akan membuang-buang waktu Anda karena itu adalah kesempatan yang baik untuk menyebutkan Anda harus menggandakan garis miring terbalik (\\ ) bila Anda ingin menggunakannya sebagai pembatas:

sh$ paste -d'/\\' \
          - ACCOUNT*.csv CREDIT.csv DEBIT.csv - < /dev/null | tail -5
/MISCELLANEOUS CHARGES\657991/\00000000015,00/
/VAT BS/DEBIT\445333/\00000000003,00/
/PAYABLES\4356/00000000018,00\/
/LANDLINE TELEPHONE\626510/\00000000069,14/
/VAT BS/ENC\445452/\00000000013,83/

7. Pembatas karakter multibyte

Seperti kebanyakan utilitas Unix standar, perintah tempel lahir pada saat satu karakter setara dengan satu byte. Tapi ini tidak lagi terjadi:hari ini, banyak sistem menggunakan pengkodean panjang variabel UTF-8 secara default. Dalam UTF-8, sebuah karakter dapat diwakili oleh 1, 2, 3 atau 4 byte. Itu memungkinkan kami untuk menggabungkan dalam file teks yang sama seluruh variasi tulisan manusia— serta berton-ton simbol dan emoji— sambil mempertahankan kompatibilitas yang meningkat dengan pengkodean karakter US-ASCII satu byte yang lama.

Katakanlah misalnya saya ingin menggunakan WHITE DIAMOND (◇ U+25C7) sebagai pemisah bidang saya. Dalam UTF-8, karakter ini dikodekan menggunakan tiga byte e2 97 87 . Karakter ini mungkin sulit didapatkan dari keyboard, jadi jika Anda ingin mencobanya sendiri, saya sarankan Anda copy-paste dari blok kode di bawah ini:

# The sed part is only used as a little trick to add the
# row number as the first field in the output
sh$ sed -n = ACCOUNTNUM.csv |
       paste -d'◇' - ACCOUNT*.csv | tail -5
26�MISCELLANEOUS CHARGES�657991
27�VAT BS/DEBIT�445333
28�PAYABLES�4356
29�LANDLINE TELEPHONE�626510
30�VAT BS/ENC�445452

Cukup menipu, bukan? Alih-alih berlian putih yang diharapkan, saya memiliki simbol "tanda tanya" itu (setidaknya, inilah yang ditampilkan di sistem saya). Ini bukan karakter "acak". Ini adalah karakter pengganti Unicode yang digunakan “untuk menunjukkan masalah ketika sistem tidak dapat merender aliran data ke simbol yang benar” . Jadi, apa yang salah?

Sekali lagi, memeriksa konten biner mentah dari output akan memberi kita beberapa petunjuk:

sh$ sed -n = ACCOUNTNUM.csv | paste -d'◇' - ACCOUNT*.csv | tail -5 | hexdump -C
00000000  32 36 e2 4d 49 53 43 45  4c 4c 41 4e 45 4f 55 53  |26.MISCELLANEOUS|
00000010  20 43 48 41 52 47 45 53  97 36 35 37 39 39 31 0a  | CHARGES.657991.|
00000020  32 37 e2 56 41 54 20 42  53 2f 44 45 42 49 54 97  |27.VAT BS/DEBIT.|
00000030  34 34 35 33 33 33 0a 32  38 e2 50 41 59 41 42 4c  |445333.28.PAYABL|
00000040  45 53 97 34 33 35 36 0a  32 39 e2 4c 41 4e 44 4c  |ES.4356.29.LANDL|
00000050  49 4e 45 20 54 45 4c 45  50 48 4f 4e 45 97 36 32  |INE TELEPHONE.62|
00000060  36 35 31 30 0a 33 30 e2  56 41 54 20 42 53 2f 45  |6510.30.VAT BS/E|
00000070  4e 43 97 34 34 35 34 35  32 0a                    |NC.445452.|
0000007a

Kami sudah memiliki kesempatan untuk berlatih dengan hex dump di atas, jadi mata Anda sekarang harus cukup tajam untuk melihat pembatas bidang dalam aliran byte. Dengan melihat lebih dekat, Anda akan melihat pemisah bidang setelah nomor baris adalah byte e2 . Tetapi jika Anda melanjutkan penyelidikan, Anda akan melihat pemisah kolom kedua adalah 97 . Tidak hanya paste perintah tidak menampilkan karakter yang saya inginkan, tetapi juga tidak menggunakan byte yang sama di mana-mana sebagai pemisah?!?

Tunggu sebentar:bukankah itu mengingatkan Anda akan sesuatu yang sudah kita bicarakan? Dan dua byte itu e2 97 , bukankah mereka agak akrab bagi Anda? Yah, familiar mungkin sedikit berlebihan, tetapi jika Anda melompat ke belakang beberapa paragraf, Anda mungkin menemukan mereka disebutkan di suatu tempat…

Jadi apakah Anda menemukan di mana itu? Sebelumnya, saya katakan di UTF-8, berlian putih dikodekan sebagai tiga byte e2 97 87 . Dan memang, paste perintah telah menganggap urutan itu bukan sebagai karakter tiga byte keseluruhan, tetapi sebagai tiga independen byte dan seterusnya, byte pertama digunakan sebagai pemisah bidang pertama, kemudian byte kedua sebagai pemisah bidang kedua.

Saya membiarkan Anda menjalankan kembali eksperimen itu dengan menambahkan satu kolom lagi di data input; Anda akan melihat pemisah bidang ketiga menjadi 87 — byte ketiga dari representasi UTF-8 untuk berlian putih.

Ok, itu dia penjelasannya:paste perintah hanya menerima "karakter" satu byte sebagai pemisah. Dan itu sangat menjengkelkan, karena, sekali lagi, saya tidak tahu cara apa pun untuk mengatasi batasan itu kecuali dengan menggunakan /dev/null trik yang sudah saya berikan kepada Anda:

sh$ sed -n = ACCOUNTNUM.csv |
    paste  -d'◇' \
           - /dev/null /dev/null \
           ACCOUNTLIB.csv /dev/null /dev/null \
           ACCOUNTNUM.csv | tail -5
26◇MISCELLANEOUS CHARGES◇657991
27◇VAT BS/DEBIT◇445333
28◇PAYABLES◇4356
29◇LANDLINE TELEPHONE◇626510
30◇VAT BS/ENC◇445452

Jika Anda membaca artikel saya sebelumnya tentang cut perintah, Anda mungkin ingat saya memiliki masalah serupa dengan implementasi GNU alat itu. Tetapi saya perhatikan saat itu implementasi OpenBSD dengan benar mempertimbangkan LC_CTYPE pengaturan lokal untuk mengidentifikasi karakter multibyte. Karena penasaran, saya telah menguji paste perintah di OpenBSD juga. Sayangnya, dengan hasil yang sama seperti pada kotak Debian saya kali ini, meskipun spesifikasi untuk paste utilitas menyebutkan variabel lingkungan LC_CTYPE sebagai menentukan ” lokal untuk interpretasi urutan byte data teks sebagai karakter (misalnya, byte tunggal sebagai lawan karakter multi-byte dalam argumen dan file input)” . Dari pengalaman saya, semua implementasi utama paste utilitas saat ini mengabaikan karakter multi-byte dalam daftar pembatas dan menganggap pemisah satu-byte. Tetapi saya tidak akan mengklaim telah mengujinya untuk seluruh variasi platform *nix. Jadi jika saya melewatkan sesuatu di sini, jangan ragu untuk menggunakan bagian komentar untuk mengoreksi saya!

Kiat Bonus:Menghindari \0 perangkap

Untuk alasan historis:

Perintah:
tempel -d “\0” …​ tempel -d “” …​
tidak selalu setara; yang terakhir tidak ditentukan oleh volume IEEE Std 1003.1-2001 ini dan dapat mengakibatkan kesalahan. Konstruk '\0' digunakan untuk berarti "tidak ada pemisah" karena versi historis tempel tidak mengikuti pedoman sintaks, dan perintah:
tempel -d”” …​
tidak dapat ditangani dengan baik oleh getopt().

Jadi, cara portabel untuk menempelkan file tanpa menggunakan pembatas adalah dengan menentukan \0 pembatas. Ini agak berlawanan dengan intuisi karena, untuk banyak perintah, \0 berarti karakter NUL–karakter yang dikodekan sebagai byte yang dibuat hanya dari nol yang tidak boleh berbenturan dengan konten teks apa pun.

Anda mungkin menemukan karakter NUL sebagai pemisah yang berguna terutama ketika data Anda mungkin berisi karakter arbitrer (seperti saat bekerja dengan nama file atau data yang disediakan pengguna). Sayangnya, saya tidak mengetahui cara apa pun untuk menggunakan karakter NUL sebagai pembatas bidang dengan paste memerintah. Tapi mungkin Anda tahu bagaimana melakukannya? Jika itu masalahnya, saya akan dengan senang hati membaca solusi Anda di bagian perintah.

Di sisi lain, paste bagian implementasi dari GNU Coreutils memiliki -z non non-standar opsi untuk beralih dari baris baru ke karakter NUL untuk pemisah baris. Namun dalam hal ini, karakter NUL akan digunakan sebagai pemisah baris keduanya untuk masukan dan keluaran. Jadi, untuk menguji fitur itu, pertama-tama kita memerlukan versi file input kita yang tidak diakhiri:

sh$ tr '\n' '\0' < ACCOUNTLIB.csv > ACCOUNTLIB.zero
sh$ tr '\n' '\0' < ACCOUNTNUM.csv > ACCOUNTNUM.zero

Untuk melihat apa yang berubah dalam prosesnya, kita dapat menggunakan hexdump utilitas untuk memeriksa konten biner mentah dari file:

sh$ hexdump -C ACCOUNTLIB.csv | head -5
00000000  41 43 43 4f 55 4e 54 4c  49 42 0a 54 49 44 45 20  |ACCOUNTLIB.TIDE |
00000010  53 43 48 45 44 55 4c 45  0a 56 41 54 20 42 53 2f  |SCHEDULE.VAT BS/|
00000020  45 4e 43 0a 50 41 59 41  42 4c 45 53 0a 41 43 43  |ENC.PAYABLES.ACC|
00000030  4f 4d 4f 44 41 54 49 4f  4e 20 47 55 49 44 45 0a  |OMODATION GUIDE.|
00000040  56 41 54 20 42 53 2f 45  4e 43 0a 50 41 59 41 42  |VAT BS/ENC.PAYAB|
sh$ hexdump -C ACCOUNTLIB.zero | head -5
00000000  41 43 43 4f 55 4e 54 4c  49 42 00 54 49 44 45 20  |ACCOUNTLIB.TIDE |
00000010  53 43 48 45 44 55 4c 45  00 56 41 54 20 42 53 2f  |SCHEDULE.VAT BS/|
00000020  45 4e 43 00 50 41 59 41  42 4c 45 53 00 41 43 43  |ENC.PAYABLES.ACC|
00000030  4f 4d 4f 44 41 54 49 4f  4e 20 47 55 49 44 45 00  |OMODATION GUIDE.|
00000040  56 41 54 20 42 53 2f 45  4e 43 00 50 41 59 41 42  |VAT BS/ENC.PAYAB|

Saya akan membiarkan Anda membandingkan sendiri dua hex dump di atas untuk mengidentifikasi perbedaan antara file ".zero" dan file teks asli. Sebagai petunjuk, saya dapat memberi tahu Anda bahwa baris baru dikodekan sebagai 0a byte.

Mudah-mudahan, Anda meluangkan waktu yang diperlukan untuk menemukan karakter NUL di file input ".zero". Bagaimanapun, kami sekarang memiliki versi file input yang diakhiri dengan nol, jadi kami dapat menggunakan -z pilihan paste perintah untuk menangani data tersebut, menghasilkan output serta hasil nol-dihentikan:

# Hint: in the hexadecimal dump:
#  the byte 00 is the NUL character
#  the byte 09 is the TAB character
# Look at any ASCII table to find the mapping
# for the letters or other symbols
# (https://en.wikipedia.org/wiki/ASCII#Character_set)
sh$ paste -z *.zero | hexdump -C | head -5
00000000  41 43 43 4f 55 4e 54 4c  49 42 09 41 43 43 4f 55  |ACCOUNTLIB.ACCOU|
00000010  4e 54 4e 55 4d 00 54 49  44 45 20 53 43 48 45 44  |NTNUM.TIDE SCHED|
00000020  55 4c 45 09 36 32 33 34  37 37 00 56 41 54 20 42  |ULE.623477.VAT B|
00000030  53 2f 45 4e 43 09 34 34  35 34 35 32 00 50 41 59  |S/ENC.445452.PAY|
00000040  41 42 4c 45 53 09 34 33  35 36 00 41 43 43 4f 4d  |ABLES.4356.ACCOM|

# Using the `tr` utility, we can map \0 to newline
# in order to display the output on the console:
sh$ paste -z *.zero | tr '\0' '\n' | head -3
ACCOUNTLIB    ACCOUNTNUM
TIDE SCHEDULE    623477
VAT BS/ENC    445452

Karena file input saya tidak berisi baris baru yang disematkan dalam data, -z pilihan kegunaan terbatas di sini. Namun berdasarkan penjelasan di atas, saya biarkan Anda mencoba memahami mengapa contoh berikut ini bekerja “seperti yang diharapkan”. Untuk memahami sepenuhnya bahwa Anda mungkin perlu mengunduh file sampel dan memeriksanya pada tingkat byte menggunakan hexdump utilitas seperti yang kami lakukan di atas:

# Somehow, the head utility seems to be confused
# by the ACCOUNTS file content (I wonder why?;)
sh$ head -3 CATEGORIES ACCOUNTS
==> CATEGORIES <==
PRIVATE
ACCOMMODATION GUIDE
SHARED

==> ACCOUNTS <==
6233726230846265106159126579914356613866618193623477623795445333445452605751
# The output is quite satisfactory, putting the account number
# after the account name and keeping things surprisingly nicely formatted:
sh$ paste -z -d':' CATEGORIES ACCOUNTS | tr '\0' '\n' | head -5
PRIVATE
ACCOMMODATION GUIDE:623372

SHARED
ADVERTISEMENTS:623084

Apa lagi?

paste perintah hanya menghasilkan keluaran teks yang dibatasi. Tetapi seperti yang diilustrasikan di akhir video pengantar, jika sistem Anda mendukung column BSD utilitas, Anda dapat menggunakannya untuk mendapatkan tabel yang diformat dengan baik dengan mengonversi paste output perintah ke format teks lebar tetap. Tapi itu akan menjadi subjek artikel yang akan datang. Jadi pantau terus, dan seperti biasa, jangan lupa untuk membagikan artikel itu di situs web dan media sosial favorit Anda!


Linux
  1. Perintah Sed Linux:Penggunaan dan Contoh

  2. 4 Penggunaan Cut Command yang Esensial dan Praktis di Linux

  3. Perintah mv di Linux:7 Contoh Penting

  1. Perintah Linux Cat:Penggunaan dan Contohnya

  2. Perintah Linux:pekerjaan, bg, dan fg

  3. Perintah Linux df

  1. Perintah AWK Linux – Contoh Sintaks Penggunaan Linux dan Unix

  2. 5 Contoh Praktis Perintah "cd" di Linux

  3. 16 Contoh Praktis Perintah Traceroute di Linux