6

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
wjandrea
  • 14,236
  • 4
  • 48
  • 98
Josselin
  • 193
  • 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 08 '18 at 07:57
  • @Melebius, l get the same message -bash: /usr/bin/xargs: Argument list too long either with -L1 or L – Josselin Oct 08 '18 at 08:12
  • @Melebius, please see me edit – Josselin Oct 08 '18 at 08: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 08 '18 at 09:30

1 Answers1

6

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.

Melebius
  • 11,431
  • 9
  • 52
  • 78
  • 2
    I think he wants -mindepth 2 -maxdepth 2, which would be the equivalent to */*. – pLumo Oct 08 '18 at 08:46
  • @Melebius, as mentionned in the top of my post details are described in Rename files by adding their parent folder name – Josselin Oct 08 '18 at 09:03
  • @Melebius. It seems to work it's still running. I let you know – Josselin Oct 08 '18 at 09:04
  • 1
    @Rovo you are write find . -maxdepth 2 -type f -exec rename -n 's/(.*)//$1/$1_/' {} ; describes my need – Josselin Oct 08 '18 at 09: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 [edit]ing or comments. https://askubuntu.com/help/someone-answers – Melebius Dec 05 '18 at 09:49