This question already has an answer here:

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


xargs -L  rename 's/(.*)\//$1\/$1_/' */*
xargs -L1  rename 's/(.*)\//$1\/$1_/' */*

Same error:

-bash: /usr/bin/xargs:  Argument list too long

marked as duplicate by Sergiy Kolodyazhnyy command-line Oct 8 '18 at 9:29

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 2
    An unquoted */* is always expanded by the shell; if you have too many matching files then it'll always be an "Argument list too long" even before xargs could get to do its business. The point of xargs is that it reads the list of files from stdin instead of parameters, that is, you should not have a final */*. The ls or find command is supposed to list the filenames. – egmont Oct 8 '18 at 7:57
  • @Melebius, l get the same message -bash: /usr/bin/xargs: Argument list too long either with -L1 or L – Josselin Oct 8 '18 at 8:12
  • @Melebius, please see me edit – Josselin Oct 8 '18 at 8:31
  • See the linked duplicate. When dealing with argument list too long error you either have to use find with -exec flag or a for loop. – Sergiy Kolodyazhnyy Oct 8 '18 at 9:30

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.

  • 2
    I think he wants -mindepth 2 -maxdepth 2, which would be the equivalent to */*. – RoVo Oct 8 '18 at 8:46
  • @Melebius, as mentionned in the top of my post details are described in Rename files by adding their parent folder name – Josselin Oct 8 '18 at 9:03
  • @Melebius. It seems to work it's still running. I let you know – Josselin Oct 8 '18 at 9:04
  • 1
    @Rovo you are write find . -maxdepth 2 -type f -exec rename -n 's/(.*)\//$1\/$1_/' {} \; describes my need – Josselin Oct 8 '18 at 9:05
  • @Josselin Were you satisfied with my answer? Then please give me an upvote (∧). If I could solve your problem, it would be nice if you accepted my answer (✓). In the opposite case, please clarify your needs using editing or comments. askubuntu.com/help/someone-answers – Melebius Dec 5 '18 at 9:49

Not the answer you're looking for? Browse other questions tagged or ask your own question.