0

I'm using zsh on MX Linux 23.2.

For years I have tried to figure out why a command like

find . -depth -type f -execdir rename 's/_720p//' {} \; 

skips over files.

I know my file manager can't be trusted to show the changes, so I check by typing ls into the terminal.  Lo and behold!  There are files listed there with '_720p' still in the name.

I've tried sending the process to the background and using wait, but I get the same results.  The only thing I have found is something like

while [ ! .(NF) ]; do filename=$(find . -type f -print0 -quit) rename 's/_720p//' $filename mv $filename $HOME/Videos done 

I've never seen another question even remotely similar to this one.  Am I the only person in the Linuxverse who can't get it right?  What is the problem?

5
  • 2
    Can filenames contain more than a single occurrence of _720p? Because afaik rename 's/_720p//' would only replace the first such occurrence Commented Apr 27, 2024 at 12:10
  • (1) Beside running the command in the background (which was not likely to help), what have you done to debug this?  (2) Can you create a scenario in which the error occurs?  Does it occur consistently?  Show us.  (3) If you run your command a second time, does it catch some or all of the files it missed?    Please do not respond in comments; edit your question to make it clearer and more complete. Commented Apr 27, 2024 at 12:20
  • According to this man page, rename (or some versions of it) requires at least three parameters: <expression> <replacement> <file> .... Commented Apr 28, 2024 at 0:01
  • Will add a proper script and output soon. Commented May 1, 2024 at 21:18
  • I've run a few tests and now believe I was premature in blaming find. I've tried various renaming methods with less than 100% success, so my problems probably lie elsewhere. My scripting skills, obviously, need the most work. Thanks to all who tried to help. I tried to delete this question but cannot. How can I mark to as withdrawn? Commented May 3, 2024 at 11:23

1 Answer 1

1

s/_720p// only replaces the first occurrence of _720p with nothing, so it would rename a foo_720p_bar_720p file to foo_bar_720p.

You need to add the g flag to substitute every occurrence: s/_720p//g, but even then, a file called foo_72_720p0p for instance only has one occurrence of _720p but would be renamed to foo_720p once that occurrence has been removed.

You'd need while (s/_720p//g) {} in that case to retry the substitution until it doesn't find anything.

Also note that some perl-based rename implementations have a -d option to only operate on the base name of the files which would save having to run one rename per file¹

find . -depth -name '*_720p*' -type f -exec rename -d ' while (s/_720p//g) {}' {} + 

Note that zsh has a batch renamer built-in in the zmv autoloadable function:

autoload -Uz zmv zmv '(**/)(*_720p*)(#q.)' '$1$2:gs/_720p//' 

Would replace all the occurrences. To handle the _72_72_720p0p0p cases:

zmv '(**/)(*_720p*)(#q.)' '$1$2:fs/_720p//' 

Where the f causes the following s modifier to be repeated until there's no modification.


¹ But would not benefit from the safety improvements of -execdir. Note that some find implementations support {} + for -execdir as well, though it still needs to run at least one rename per directory.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.