Как сделать `head` и` tail` для ввода с нулем в bash?

18

findКоманда может выводить имена файлов в виде строк, разделенных нулем (если -print0есть), и xargsможет использовать их с -0включенной опцией. Но между ними, это трудно манипулировать , что набор файлов - sortкоманда имеет -zпереключатель, который дает возможность сортировать эти файлы, но headи tailих не имеет.

Как я могу сделать , headи tailна этих нуль-разделителями входы в удобном виде? (Я всегда могу создать короткий и медленный скрипт ruby, но я надеюсь, что мог бы быть лучший способ)

Рогач
источник

Ответы:

21

GNU headи tailначиная с версии 8.25 для coreutils есть -zопция для этого.

В старых версиях или для систем , отличных от GNU, вы можете попробовать и своп \0и \n:

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

Обратите внимание, что некоторые headреализации не могут справиться с NUL-символами (и это не требуется для POSIX), но там, где find поддерживает -print0, headи текстовые утилиты обычно поддерживают NUL-символы.

Вы также можете использовать функцию для переноса любой команды между двумя trs:

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

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

Имейте в виду, что под nul_terminated, \0подразумевается символ новой строки. Так, например, заменить \nна _:

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

( \x0будучи также расширением GNU).

Если вам нужно выполнить более одной команды фильтрации , вы можете сделать:

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

Но это означает выполнение нескольких избыточных trкоманд. Кроме того, вы можете запустить:

find ... -print0 | nul_terminated eval 'cmd1 | cmd2' | xargs -r0 ...
Стефан Шазелас
источник
2
Разве это не устраняет основную причину использования \x0вместо \nразграничения значений? (¹ так что вы можете справиться со значениями, которые могут содержать \n)
Thedward
@Thedward, нет, напротив, -print0 | tr '\n\0' '\0\n'есть строки, представляющие пути к файлам, в которые были преобразованы символы новой строки в них \0. Итак, если вы берете первую строку с head -n 1и \0снова конвертируете s обратно в новые строки tr '\0\n' '\n\0', вы получаете первый путь к файлу, разделенный NUL, со встроенными символами новой строки.
Стефан Шазелас