Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

find command can output names of files as a null-delimited strings (if -print0 is provided), and xargs can consume them with -0 option turned on. But in between, it's hard to manipulate that collection of files - sort command has -z switch, that makes it possible to sort those files, but head and tail don't have them.

How can I do head and tail on those null-delimited inputs in a convenient way? (I can always create a short & slow ruby script, but I hope that there could be a better way)

share|improve this question

1 Answer 1

up vote 12 down vote accepted

Just swap \0 and \n:

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

Note that some head implementations can't cope with NUL characters (and they're not required to by POSIX), but where find supports -print0, head and text utilities generally support NUL characters.

You can also use a function to wrap any command between the two trs:

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

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

Keep in mind that under nul_terminated, a \0 means a newline character. So for instance, to replace \n with _:

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

(\x0 being also a GNU extension).

If you need to run more than one filtering command, you can do:

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

But that means running a few redundant tr commands. Alternatively, you can run:

find ... -print0 | nul_terminated eval 'cmd1 | cmd2' | xargs -r0 ...
share|improve this answer
    
Doesn't this defeat the primary reason¹ for using \x0 instead of \n to delimit the values? (¹ so you can cope with values that might contain \n) –  Thedward Nov 12 at 22:02
    
@Thedward, no, on the contrary -print0 | tr '\n\0' '\0\n' has lines representing the file paths where newline characters in them have been converted to \0. So, if you take the first line with head -n 1 and convert the \0s back to newlines with tr '\0\n' '\n\0' again, you've got the first file path NUL-delimited with its embedded newline characters. –  Stéphane Chazelas Nov 12 at 22:08

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.