Bagaimana melakukan `head` dan` tail` pada input pembatas nol di bash?

18

findperintah dapat menampilkan nama file sebagai string yang dibatasi-nol (jika -print0disediakan), dan xargsdapat menggunakannya dengan -0opsi yang dihidupkan. Tetapi di antara keduanya, sulit untuk memanipulasi kumpulan file itu - sortperintah telah -zberalih, yang memungkinkan untuk mengurutkan file-file itu, tetapi headdan tailtidak memilikinya.

Bagaimana saya bisa melakukan headdan tailpada input yang dibatasi nol itu dengan cara yang mudah? (Saya selalu dapat membuat skrip ruby ​​pendek & lambat, tapi saya harap ada cara yang lebih baik)

Rogach
sumber

Jawaban:

21

GNU headdan tailkarena coreutils versi 8.25 memiliki -zopsi untuk itu.

Dengan versi yang lebih lama atau untuk sistem non-GNU, Anda dapat mencoba dan bertukar \0dan \n:

find ... -print0 |
  tr '\0\n' '\n\0' |
  head |
  tr '\0\n' '\n\0'

Perhatikan bahwa beberapa headimplementasi tidak dapat mengatasi karakter NUL (dan mereka tidak diharuskan oleh POSIX), tetapi di mana menemukan dukungan -print0, headdan utilitas teks umumnya mendukung karakter NUL.

Anda juga dapat menggunakan fungsi untuk membungkus perintah apa pun di antara keduanya tr:

nul_terminated() {
  tr '\0\n' '\n\0' | "$@" | tr '\0\n' '\n\0'
}

find ... -print0 | nul_terminated tail -n 12 | xargs -r0 ...

Perlu diingat bahwa di bawah nul_terminated, \0berarti karakter baris baru. Jadi misalnya, untuk mengganti \ndengan _:

find . -depth -name $'*\n*' -print0 | nul_terminated sed '
  p;h;s,.*/,,;s/\x0/_/g;H;g;s,[^/]*\n,,' | xargs -r0n2 mv

( \x0menjadi juga ekstensi GNU).

Jika Anda perlu menjalankan lebih dari satu perintah pemfilteran , Anda dapat melakukan:

find ... -print0 |
  nul_terminated cmd1 |
  nul_terminated cmd2 | xargs -r0 ...

Tetapi itu berarti menjalankan beberapa trperintah yang berlebihan . Atau, Anda dapat menjalankan:

find ... -print0 | nul_terminated eval 'cmd1 | cmd2' | xargs -r0 ...
Stéphane Chazelas
sumber
2
Bukankah ini mengalahkan alasan utama primary untuk menggunakan \x0alih-alih \nmembatasi nilai? (¹ sehingga Anda dapat mengatasi nilai-nilai yang mungkin mengandung \n)
Thedward
@Thedward, tidak, sebaliknya -print0 | tr '\n\0' '\0\n'memiliki garis-garis yang mewakili jalur file tempat karakter baris baru di dalamnya telah dikonversi \0. Jadi, jika Anda mengambil baris pertama dengan head -n 1dan mengonversi \0kembali ke baris baru dengan tr '\0\n' '\n\0'lagi, Anda punya jalur file pertama NUL-dibatasi dengan karakter baris baru yang tertanam.
Stéphane Chazelas