Jak wykonać polecenie „głowa” i „ogon” na wejściu rozdzielanym zerami w bash?

18

findpolecenie może wyświetlać nazwy plików jako ciągi rozdzielane znakiem null (jeśli -print0jest podany) i xargsmoże je wykorzystywać przy -0włączonej opcji. Ale w międzyczasie, to trudno manipulować, że zbiór plików - sortpolecenie -zprzełącznik, który umożliwia sortowanie te pliki, ale headi tailnie mają.

Jak mogę to zrobić headi tailna tych ograniczonych zerami danych wejściowych w wygodny sposób? (Zawsze mogę stworzyć krótki i wolny skrypt ruby, ale mam nadzieję, że może być lepszy sposób)

Rogach
źródło

Odpowiedzi:

21

GNU headi tailod Coreutils w wersji 8.25 mają taką -zopcję.

W starszych wersjach lub dla systemów innych niż GNU możesz spróbować zamienić \0i \n:

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

Zauważ, że niektóre headimplementacje nie radzą sobie ze znakami NUL (i nie jest to wymagane przez POSIX), ale tam, gdzie find obsługuje -print0, heada narzędzia tekstowe ogólnie obsługują znaki NUL.

Możesz także użyć funkcji, aby zawinąć dowolne polecenie między dwoma trs:

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

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

Należy mieć na uwadze, że na mocy nul_terminated, a \0oznacza znak nowej linii. Tak na przykład, aby zastąpić \nz _:

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

( \x0będący również rozszerzeniem GNU).

Jeśli chcesz uruchomić więcej niż jedno polecenie filtrowania , możesz:

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

Ale to oznacza uruchomienie kilku zbędnych trpoleceń. Alternatywnie możesz uruchomić:

find ... -print0 | nul_terminated eval 'cmd1 | cmd2' | xargs -r0 ...
Stéphane Chazelas
źródło
2
Czy to nie pokonuje podstawowego powodu¹ używania \x0zamiast \nograniczania wartości? (¹ więc \n
poradzisz
@Thedward, nie, wręcz przeciwnie, -print0 | tr '\n\0' '\0\n'mają wiersze reprezentujące ścieżki do plików, w których konwertowane są znaki nowej linii \0. Tak więc, jeśli weźmiesz pierwszy wiersz head -n 1i ponownie przekonwertujesz \0s z powrotem na nowe wiersze tr '\0\n' '\n\0', masz pierwszą ścieżkę pliku rozdzieloną NUL z osadzonymi znakami nowego wiersza.
Stéphane Chazelas