Copy files in batch, renaming them with the name of the original directory

Suppose I have a directory structure organized as follows on my PC:

Diretorio 01
  Arquivo 01.jpg
  Arquivo 02.jpg
  Arquivo 03.jpg
  Arquivo 04.jpg
Diretorio 02
  Arquivo 01.jpg
  Arquivo 02.jpg
Diretorio 03
  Arquivo 01.jpg
  Arquivo 02.jpg
  Arquivo 03.jpg
...
Diretorio n
  Arquivo 01.jpg
  Arquivo 02.jpg
  Arquivo 03.jpg
  Arquivo 04.jpg

Are n different directories. Inside each of them I have a variable number of files .jpg. I would like to copy these files .jpg to another folder on my computer, putting them all in the same place and renaming them as follows in the process:

Diretorio 01 Arquivo 01.jpg
Diretorio 01 Arquivo 02.jpg
Diretorio 01 Arquivo 03.jpg
Diretorio 01 Arquivo 04.jpg
Diretorio 02 Arquivo 01.jpg
Diretorio 02 Arquivo 02.jpg
Diretorio 03 Arquivo 01.jpg
Diretorio 03 Arquivo 02.jpg
Diretorio 03 Arquivo 03.jpg
...
Diretorio n Arquivo 01.jpg
Diretorio n Arquivo 02.jpg
Diretorio n Arquivo 03.jpg
Diretorio n Arquivo 04.jpg

That is, each resulting file will be named according to the source directory and the original name of the file. Note that file names repeat within the source directories.

Originally my files have spaces in the names, but this space does not need to be present in the final result. That is, names can be something in line Diretorio_01_Arquivo_01.jpg if this makes the algorithm easier to implement.

Author: Marcus Nunes, 2018-07-22

1 answers

Assuming the names are random, both of the folders and the files, what will suffice will be a recursive function to take the photos, use the cp and copy to a new destination, something like

  • /home/docs/pasta/foo.jpg ➡️ /home/target/pasta_foo.jpg

The" function " inside the bash could be something like move_recursive, so with the command cp will move the file to the desired destination (you can exchange for mv if you want to move for good, which I do not recommend since the script was not 100% tested), so this:

echo "cp \"$file\" \"${destination_path}${only_dirname}_${only_filename}\""

Should be this:

cp "$file" "${destination_path}${only_dirname}_${only_filename}"

Or this:

mv "$file" "${destination_path}${only_dirname}_${only_filename}"

Note that I used ${...} to be able to work with underline, because if I did this $only_dirname_$only_filename would fail.

I put in a echo the command cp to avoid executing without being sure that it worked, look at the result of all command and will know if it is executing correctly

To pick up only the name of the file or folder I used:

$(basename $current_path)

Or script all it should look like this:

#!/bin/bash

# "função" para recursividade
move_recursive() {
    echo ""
    echo "-------------------------"
    echo "Lendo pasta: $path"
    echo "-------------------------"

    current_path="$1"

    for file in "$1"/*
    do
        if [ -d "$file" ]
        then
            move_recursive "$file"
        elif [ -f "$file" ]
        then
            only_dirname=$(basename $current_path)
            only_filename=$(basename "$file")

            # tire do echo para executar
            echo "cp \"$file\" \"${destination_path}${only_dirname}_${only_filename}\""
        fi
    done
}

# pasta de destino (troque pela pasta de destino, caminho completo)
destination_path="/home/destination/"

# pasta aonde estão as fotos (troque pelo caminho completo desejado)
source_path="/home/bar/"

move_recursive $source_path

Swapping whitespace for underline / underscore with bash

I couldn't test because my system isn't unix-like, so I can't state if it works, but I believe if to use it this way:

echo "cp \"$file\" \"${destination_path}${only_dirname//[[:blank:]]/_}_${only_filename//[[:blank:]]/_}\""

All spaces will be exchanged for _, in a practical example, this would be:

#!/bin/bash

foo="a b c d"

echo ${foo//[[:blank:]]/_}

Being [[:blank:]] the regular expression for whitespace (TABs too) and after the / would be the character that will replace.

 2
Author: Guilherme Nascimento, 2018-07-22 19:20:29