I try to execute basename via find like this:
find ./test_folder -type f -exec basename {} +
But I get the following error:
basename: extra operand './test_folder/test/file.crt'
Why I get this though?
POSIX basename
only supports this:
basename string [suffix]
What happens when providing more than two strings¹ is not specified by POSIX but in most if not all implementations results in a syntax error such as the extra operand
one you're getting.
But even two strings are too many in your case because the second one would be interpreted as a suffix
to remove. You don't want to specify suffix
, so with POSIX basename
you are limited to this:
basename string
i.e. to one string per invocation of basename
. The syntax to invoke a separate basename
for each pathname from find
is:
find … -exec basename {} \;
(read Understanding the -exec
option of find
to get the difference between ;
and +
).
The GNU, ast-open, toybox and FreeBSD implementations of basename
at least support -a
(aliased to --multiple
in GNU basename
and --all
in ast-open's) that allows them to work with -exec … +
of find
. With this option no operand is interpreted as a suffix
to remove (use -s …
if you need to remove suffixes). Example:
find … -exec basename -a {} +
But if you're on a GNU system, your find
already has the capability to print the basename (tail) of the found files (and has had it decades before GNU basename
added -a
/--multiple
) via its -printf
predicate:
find … -printf '%f\n'
In zsh recursive globbing, you can use the :t
modifier (from csh's history and parameter expansion from the late 70s) in a glob qualifier to get the t
ail of those paths:
print -rC1 -- test_folder/**/*(ND.:t)
(with also N
ullglob, D
otglob qualifiers and .
as the equivalent of find
's -type f
).
¹ Strictly speaking, like most utilities, it also accepts --
to signify the end of options, even if there's no option that POSIX specifies for basename
. You use it for basename -- -file-.jpg .jpg
or in basename -- "$file"
when you can't guarantee $file
won't start with -
.
find
, -printf
can be used to get the same result without using basename
at all.
Commented
Nov 6, 2023 at 20:02
find
could provide the basename of the file without running an external command, -printf "%f\n"
. From the man: Print the basename; the file's name with any leading directories removed (only the last element).