Piping `find` to 'tail`
The following should work on absolutely any paths.
Declare a function to be able to use head
and tail
on NUL-separated output:
nul_terminated() {
tr '\0\n' '\n\0' | "$@" | tr '\0\n' '\n\0'
}
Then you can use it to get a NUL-separated list of paths from your search after passing through tail
:
find . -exec printf '%s\0' {} \; | nul_terminated tail -n 2
You can then pipe that to xargs
and add your options:
find . -iname "*FooBar*" -exec printf '%s\0' {} \; | nul_terminated tail -n 2 | xargs -I "{}" -0 cp "{}" "dest"
Explanation:
find
files in the current directory (.
) and below with a name containingfoobar
(case insensitive because of thei
in-iname
);- for each file, run (
-exec
) a command to - print each file path (
{}
) followed by a NUL character (\0
) individually (\;
); - swap newlines and NUL characters (
tr '\0\n' '\n\0'
);" - get the last two lines (that is, paths;
tail -n 2
,"$@"
); - swap newlines and NUL characters again to get a NUL-separated list of file names (
tr '\0\n' '\n\0'
).
The xargs
command is a bit harder to explain. It builds as many cp ... "dest"
commands as necessary to fit in the maximum command length of the operating system, replacing the {}
token in the command with the actual file name (-I "{}" ... "{}"
), using the NUL character as a separator when reading the parameters (-0
).
You can try
cp $(find . -iname "*FooBar*" | tail -2 ) dest
find . -iname "*FooBar*"|tail -n2|xargs -i cp "{}" dest
Unfortunately this won't work with filenames that contain spaces or newlines.