-1

I'm searching for a find command to copy all wallpaper files that look like this:

3245x2324.png (All Numbers are just a placeholder) 3242x3242.jpg

I'm in my /usr/share/wallpapers folder and there are many sub folders with the files I want to copy. There are many like "screenshot.png" and these files I don't want to copy.

My find command is like this:

find . -type f -name "*????x????.???"

If I search with this I get the files I wanted to see, but if I combine this with -exec cp:

find . -type f -name "*????x????.???" -exec cp "{}" /home/mine/Pictures/WP \;

the find command only copies 10 files and there are 77 (I counted with wc).

Does anyone know what I'm doing wrong?

tripleee
  • 175,061
  • 34
  • 275
  • 318
Rongse
  • 11
  • 2
  • maybe this will help you https://stackoverflow.com/questions/26234041/is-it-possible-to-pipe-the-results-of-find-to-a-copy-command-cp – kara Dec 23 '22 at 09:46
  • it was helpful, but it doesnt seem to work with the subfolders – Rongse Dec 23 '22 at 09:57
  • 8
    Maybe you have multiple directories each containing an image `1920x1080.jpg` and they get overwritten because you can't have two files with the same name in your destination directory. – Mark Setchell Dec 23 '22 at 10:06
  • omg...that makes sense...but how do i rename them in the find command? :D – Rongse Dec 23 '22 at 11:13

2 Answers2

0

You can look it up if you follow the link. renaming with find You can use -exec to do this. But i'm not sure you can do rename and copy in one take.Maybe with a script that got executed after every find result.

But that's only a suggestion.

kara
  • 1
0

One idea/approach is to copy absolute path of the file in question to the destination, but replace the / with an underscore _ since / is not allowed in file names, at least in a Unix like environment.

With find and bash, Something like.

find /usr/share/wallpapers -type f -name "????x????.???" -exec bash -c '
   destination=/home/mine/Pictures/WP/
   shift
   for f; do
     path_name=${f%/*}
     file_name=${f##*/}
     echo cp -vi -- "$f" "$destination${path_name//\//_}$file_name"
   done' _ {} +


With globstar nullglob shell option and Associative array from the bash shell to avoid the duplicate filenames.

#!/usr/bin/env bash

shopt -s globstar nullglob
pics=(/usr/share/wallpapers/**/????x????.???)
shopt -u globstar nullglob

declare -A dups
destination=/home/mine/Pictures/WP/

for i in "${pics[@]}"; do
  ((!dups["${i##*/}"]++)) &&
  echo cp -vi -- "$i" "$destination"
done

  • GNU cp(1) has the -u flag/option which might come in handy along the way.
  • Remove the echo if you're satisfied with the result.

Another option is to add a trailing ( ) with a number/int inside it and increment it , e.g. ????x????.???(N) where N is a number/int. Pretty much like how some gui file manager deals with duplicate file/directory names.

Something like:

#!/usr/bin/env bash

source=/usr/share/wallpapers/
destination=/home/mine/Pictures/WP/

while IFS= read -rd '' file; do
  counter=1
  file_name=${file##*/}
  if [[ ! -e "$destination$file_name" && ! -e "$destination$file_name($counter)" ]]; then
    cp -v -- "$file" "$destination$file_name"
  elif [[ -e "$destination$file_name" && ! -e "$destination$file_name($counter)" ]]; then
    cp -v -- "$file" "$destination$file_name($counter)"
  elif [[ -e "$destination$file_name" && -e "$destination$file_name($counter)" ]]; then
    while [[ -e "$destination$file_name($counter)" ]]; do
      ((counter++))
    done
    cp -v -- "$file" "$destination$file_name($counter)"
  fi
done < <(find "$source" -type f -name '????x????.???' -print0)

  • Note that the -print0 primary is a GNU/BSD find(1) feature.
Jetchisel
  • 7,493
  • 2
  • 19
  • 18