0

I have 31 directories from sample1 to sample31 with similar naming files.

❯ find . -maxdepth 2 -type f ./sample5/palette-david-clode-2B4dYFgYAyQ-unsplash.thumbnail.jpg ./sample5/david-clode-2B4dYFgYAyQ-unsplash.jpg ./sample5/david-clode-2B4dYFgYAyQ-unsplash.thumbnail.jpg ./sample2/amy-syiek-0n9lbdiAKi0-unsplash.jpg ./sample2/amy-syiek-0n9lbdiAKi0-unsplash.thumbnail.jpg ./sample2/palette-amy-syiek-0n9lbdiAKi0-unsplash.thumbnail.jpg ./sample3/marc-meyer-9JE6BLqMYYM-unsplash.thumbnail.jpg ./sample3/palette-marc-meyer-9JE6BLqMYYM-unsplash.thumbnail.jpg ./sample3/marc-meyer-9JE6BLqMYYM-unsplash.jpg ...more files 

Now I'd like to

  • change all files starting with palette- to palette.jpg. Foe example: ./sample5/palette-david-clode-2B4dYFgYAyQ-unsplash.thumbnail.jpg to ./sample5/palette.jpg.

  • change all files ending with .thumbnail.jpg to sample.jpg. For example: ./sample5/david-clode-2B4dYFgYAyQ-unsplash.thumbnail.jpg to ./sample5/sample.jpg.

How can I do this on the terminal?

I tried this but didn't work:

for dir in */; do; for file in "palette-*.jpg"; do mv "$file" "palette.jpg"; done;for file in "*.thumbnail.jpg"; do mv "$file" "sample.jpg";done;done 

Result:

mv: rename palette-*.jpg to palette.jpg: No such file or directory mv: rename *.thumbnail.jpg to sample.jpg: No such file or directory mv: rename palette-*.jpg to palette.jpg: No such file or directory mv: rename *.thumbnail.jpg to sample.jpg: No such file or directory mv: rename palette-*.jpg to palette.jpg: No such file or directory ... 
4
  • Wouldn't palette-david-clode-2B4dYFgYAyQ-unsplash.thumbnail.jpg have been renamed into sample.jpg according to the first rule - so the 2:nd rule wouldn't get the chance to rename it into palette.jpg? Commented Dec 28, 2020 at 9:19
  • These are two different files. The file names with palette- move to palette.jpg. So move them first then move *.thumbnail.jpg to sample.jpg? Commented Dec 28, 2020 at 9:26
  • Ok, so you mean to reverse 1 and 2? Do 2 first, then 1? Commented Dec 28, 2020 at 9:28
  • yes, that's right. Commented Dec 28, 2020 at 9:39

3 Answers 3

3

The expanded wildcard includes the directory name. To rename a file but keep it in the same directory, keep the directory name. Your current attempt would replace the directory and the name with just a file name, effectively moving all files to the current directory.

for dir in */; do for file in "$dir"/palette-*.jpg; do mv "$file" "$dir/palette.jpg" done for file in "$dir"/*.thumbnail.jpg; do mv "$file" "$dir/sample.jpg" done done 

Notice also how the wildcards need to be outside the quotes.

Obviously, if any of the wildcards match more than one file, the last mv in the loop will overwrite all the previous ones in that directory.

Sign up to request clarification or add additional context in comments.

2 Comments

One liner: ❯ for dir in */; do for file in "$dir"/palette-*.jpg; do mv "$file" "$dir/palette.jpg"; done; for file in "$dir"/*.thumbnail.jpg; do mv "$file" "$dir/sample.jpg" ; done; done
That seems like a bad idea, but you can replace each newline except the ones after do with a semicolon, like you already had in your original code.
0

You could still use the initial find but add -name to filter out the files you'd like to rename:

#!/bin/bash # rule 2 while IFS= read -r -d $'\0' path do dir="$(dirname "$path")" echo mv "$path" "$dir/palette.jpg" mv "$path" "$dir/palette.jpg" done < <(find sample* -maxdepth 2 -type f -name 'palette*.jpg' -print0) # rule 1 while IFS= read -r -d $'\0' path do dir="$(dirname "$path")" echo mv "$path" "$dir/sample.jpg" mv "$path" "$dir/sample.jpg" done < <(find sample* -maxdepth 2 -type f -name '*.thumbnail.jpg' -print0) 

Output (for the sample files you've provided):

mv sample2/palette-amy-syiek-0n9lbdiAKi0-unsplash.thumbnail.jpg sample2/palette.jpg mv sample3/palette-marc-meyer-9JE6BLqMYYM-unsplash.thumbnail.jpg sample3/palette.jpg mv sample5/palette-david-clode-2B4dYFgYAyQ-unsplash.thumbnail.jpg sample5/palette.jpg mv sample2/amy-syiek-0n9lbdiAKi0-unsplash.thumbnail.jpg sample2/sample.jpg mv sample3/marc-meyer-9JE6BLqMYYM-unsplash.thumbnail.jpg sample3/sample.jpg mv sample5/david-clode-2B4dYFgYAyQ-unsplash.thumbnail.jpg sample5/sample.jpg 

Comments

0

If using GNU find, you can use the -execdir option:

find . -maxdepth 2 -type f -name "palette-*.jpg" -execdir mv \{\} palette.jpg \; 

This will run the mv with its current working directory set to the one each file is in, so you don't have to worry about adding it to the destination file path.

3 Comments

{} need not be escaped, it doesn't expand to anything in bash. And without -mindepth 2 this will rename files in the current directory as well.
@oguzismail The find man page says to escape {}, so I always do.
It says might need to be escaped, but not a bad habit anyway

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.