"-bash: /usr/bin/rename: Argument list too long" [duplicate]
I would like to rename files within each sub-directory by adding the name of the sub-directory. Following the answer from Rename files by adding their parent folder name, I tried:
rename 's/(.*)\//$1\/$1_/' */*
However for lots of sub-directories it doesn't work. I have 13,000 sub-directories each containing about 300 files. I get
-bash: /usr/bin/rename: Argument list too long
I tried:
ls | xargs rename 's/(.*)\//$1\/$1_/' */*
find . -maxdepth 1 -type f -print0 | xargs rename 's/(.*)\//$1\/$1_/' */*
Both give the same error:
-bash: /usr/bin/xargs: Argument list too long
EDIT
xargs -L rename 's/(.*)\//$1\/$1_/' */*
xargs -L1 rename 's/(.*)\//$1\/$1_/' */*
Same error:
-bash: /usr/bin/xargs: Argument list too long
As @egmont noted, giving the paths (*/*
) as argument(s) to xargs
is wrong. This command reads file names from the standard input instead of arguments, so issuing xargs
without any standard input (the EDIT section of the question) is useless.
Solution using ls
and xargs
Check if you can just ls
all the paths in question.
ls */*
If yes, you can use a corrected version of your 2) option:
ls */* | xargs rename -n 's/(.*)\//$1\/$1_/'
Solution using find
If you get an error from the ls
call, you can still use find
.
- This command has an
-exec
option which works similarly toxargs
, so we’ll not needxargs
in this case at all. - To mimic the behavior of
ls */*
, use the options-mindepth 2 -maxdepth 2
.
The corrected version of the 3) option would be:
find . -mindepth 2 -maxdepth 2 -type f -exec rename -n 's/(.*)\//$1\/$1_/' {} \;
The argument placeholder together with an escaped semicolon ({} \;
) ensures that rename
is run just for a single file at a time, similarly to xargs -L1
. This will prevent the original issue with too many files at once.
Dry run and actual rename
You can check the result using the -n
option I included after rename
to just list the renames it would do. To actually launch the rename operation, remove the -n
option.