"-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.

  1. This command has an -exec option which works similarly to xargs, so we’ll not need xargs in this case at all.
  2. 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.