Specifically, in mkinitcpio the command find -mindepth 1 -printf '%P\0' is used, what would be a way to recreate a command with identical output without the -printf flag. https://git.archlinux.org/mkinitcpio.git/tree/mkinitcpio This is the full script in case it is useful.
-
Do any of your file or directory names contain the newline character?meuh– meuh2018-09-18 10:33:14 +00:00Commented Sep 18, 2018 at 10:33
-
@meuh I don't know what files or directories it's finding, it's using it to find all the files to put into the initramfs. I don't see a reason the files or directories would have a newline character though.E5ten– E5ten2018-09-18 13:18:35 +00:00Commented Sep 18, 2018 at 13:18
2 Answers
%P will give the relative path of the file starting from the directory used as starting point, so that if find is run with some/path as starting point and it finds the pathname some/path/to/file, then %P will expand to to/file.
When GNU find is not given a starting point (as in the command given in the question), it will use the current directory (.) as the starting point. The %P format will therefore remove ./ from the found paths in this case.
To do the same thing as -printf '%P\0' with a non-GNU find implementations, assuming -mindepth is still available (as in find on BSD systems):
find . -mindepth 1 -exec sh -c '
for pathname do
printf "%s\0" "${pathname#./}"
done' sh {} +
The embedded sh -c script will get a batch of pathnames from find to work on and uses a standard parameter expansion that removes the initial ./ from the pathname before printing it with a terminating nul-character.
The same thing, but with a variable holding the single top-level directory path:
topdir=/some/path
find "$topdir" -mindepth 1 -exec sh -c '
topdir=${1%/}; shift
for pathname do
printf "%s\0" "${pathname#$topdir/}"
done' sh "$topdir" {} +
-
-mindepth 1can be written standardly with! -name .or! -path .Stéphane Chazelas– Stéphane Chazelas2023-02-09 08:54:52 +00:00Commented Feb 9, 2023 at 8:54
In -printf '%P\0' the %P is just removing the initial ./ from the front of the filename. You can do the equivalent with sed 's|^\./||'. The \0 part produces a null character instead of newline between each filename. You can convert newline to null with tr '\n' '\0'. So you can try
find . -mindepth 1 -print | sed 's|^\./||' | tr '\n' '\0'
If any names contain a newline, this will corrupt them, translating that newline to null and transform file paths such as ./foo<newline>./bar to foo<null>bar.