0

I have a problem where I need to rename just certain files after the parent folder and afterwards move these to a central folder. Is there a way to do this? I would like to run this on a Synology NAS.

Root
 |-Subf1
 |  |-File.txt
 |  |-File.doc
 |  |-Subf1subf1
 |  |  |-File.xml
 |  |  |-File.xls
 |  |-Subf1subf2
 |  |  |-File.pptx
 |  |  |-File.docx
 |
 |-Subf2
 |  |-File.txt
 |  |-File.doc
 |  |-Subf2subf1
 |  |  |-File.xml
 |  |  |-File.xls

Result should be:

Root
 |-Subf1
 |  |-Subf1.txt
 |  |-Subf1.doc
 |  |-Subf1.xml
 |  |-Subf1.xls
 |  |-Subf1.pptx
 |  |-Subf1.docx
 |
 |-Subf2
 |  |-Subf2.txt
 |  |-Subf2.doc
 |  |-Subf2.xml
 |  |-Subf2.xls

There is no problem with overwriting files as they all have different extensions.

αғsнιη
  • 41,407
Lorand G
  • 3
  • 1

2 Answers2

0
#! /bin/bash

shopt -s globstar  #enabled for '**' to match all files &directories recursively
#shopt -s dotglob  #uncomment to enable to match on hidden files/directories too

cd /path/to/directory/Root
for pathname in ./**/*; do
    [[ -f "$pathname" ]] && echo mv -v -- "$pathname" "${pathname%%/*}/${pathname%%/*}.${pathname##*.}";
done

##then remove remained empty directories
for pathname in ./**/*; do
    [[ -d "$pathname" && -z "$(ls -A -- "$pathname")" ]] && rm -r -- "$pathname";
done
  • [[ -f "$pathname" ]] checks if the $pathname is a file
  • ${pathname%%/*}: Using shell-parameter-expansion, cut the longest suffix from the pathname parameter. cuts everything up-to first slash / character.
  • ${pathname##*.}": same, but this cuts the longest prefix from the pathname parameter; cuts everything up-to last dot . character.
  • [[ -d "$pathname" ]] checks if the $pathname is a directory
  • ... && -z "$(ls -A -- "$pathname")" then checks if basename of the pathname which was a directory, is empty or not.

remove echo when you were happy with the result.

αғsнιη
  • 41,407
0

POSIXly:

cd Root &&
  LC_ALL=C find . \
    -name '.?*' -prune -o \
      -path './*/*/*' \
      -prune \
      -name '*.*' \
      -type f \
      -exec sh -c '
        ret=0
        for file do
          ext=${file##*.}
          sub=${file%/*/*}
          subname=${sub##*/}
          echo mv -i "$file" "$sub/$subname.$ext" || ret=$?
        done
        exit "$ret"' {} +

(remove echo if happy)

Empty dirs can be removed afterwards with:

find . -depth -type d -exec rmdir {} + 2> /dev/null

Or if your find supports the non-standard -empty and -delete:

find . -type d -empty -delete

(-delete implies -depth).