Home > Enterprise >  Bash script; Renaming files in /subdirectories
Bash script; Renaming files in /subdirectories

Time:10-07

I have huge file archives that I host on my old-skool BBS. The [Mystic] software isn't as forgiving or capable as Linux with long-filenames OR extended characters.

Filenames should be less than 80 characters long.

Filenames should only have chars A-Z & 1-9. No "! @ # $ % ^ &", etc - nor letters with tildes or carets over them.

Here is a sample of what one collections directories looks like:

pi@bbs:/mnt/Beers4TB/opendirs/TDC19 $ ls -all
total 28
drwxrwxr-x  6 pi pi 4096 Sep 16 08:08 .
drwxrwxr-x 11 pi pi 4096 Oct  6 15:04 ..
drwxrwxr-x  2 pi pi 4096 Sep 13 20:13 ANSi
drwxrwxr-x  2 pi pi 4096 Oct  6 21:16 Drivers
drwxrwxr-x 10 pi pi 4096 Sep 16 08:12 Games
-rw-rw-r--  1 pi pi 1056 Sep 13 20:12 INTRO.TXT
drwxrwxr-x  2 pi pi 4096 Sep 16 08:08 ListsNotes

And within /subdirectories they may go 2, 3 or more deep.

Here is a sample of what some files are currently named:

pi@bbs:/mnt/Beers4TB/opendirs/TDC19/Games/Applications $ ls M*
'Mean 18 - Golf Menu [SW] (1988)(Robert J. Butler) [Sports, Golf, Utility].zip'
'Mean 18 - M18 (1988)(Ken Hopkins) [Sports, Golf, Utility].zip'
'Metaltech- Battledrome Game Editor (1994)(Sierra On-Line, Inc.) [Utility].zip'
'Might and Magic III Character Editor (1991)(Blackbeard'\''s Ghost) [Utility].zip'
'Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].zip'

I have worked on some things that show promise... this echo/sed command removes SOME high chars:

echo "Might and Magic III Character Editor (1991)(Blackbeard'''s Ghost) [Utility].zip" | sed -r -e 's/\x27 //g' -e 's/[][")(]//g' -e 's/[ ] //g'

(It renames the file:) Might_and_Magic_III_Character_Editor_1991_Blackbeards_Ghost_Utility.zip

Then, I have a command that will rename ONE entire /subdirectory, but it DOESN'T remove any characters:

for f in *.zip; do mv "${f}" "${f//[][\")( ]/_}"; done

That's good... but I have to get rid of the high characters... and, this method adds multiple spaces in filenames sometimes - which adds to that max 80 filename limit - and theres no safegaurds built in...

I worked on adding in support for going thru multiple /subdirectories, but I KNOW that my syntax is still wrong... you can, however, see what I was attempting to do:

P=$(pwd); for D in $(find . -maxdepth 1 -type d); do cd $D; for f in *.zip; do mv "${f}" "${f//[][\")( ]/_}"; cd $P; done

So, in closing - I'm open to any Linux commands that will: Remove any characters that are NOT A-Z or 1-9. Remove any extra spaces in filenames. Make sure filenames are only 80 characters long max, simply removing the last bit before the .zip (or .anything) extension. Begin in a main /directory and rename all files in each /subdirectory within the main.

Very last; I always try to put things together first... I get help from associates second - and I come to the interwebs last... but I want to UNDERSTAND how to code this exact sort of thing myself. If you have any suggestions of where to learn, that would be received well too. I tried to post this question CORRECTLY this time, pls forgive if I haven't gotten every rule correct.

pAULIE42o . . . . . /s

CodePudding user response:

The command tr -cd deletes all characters which are not in the given list.

for f in *.zip; do
  mv "$f" "$(tr -cd 'A-Za-z0-9. \n' <<< "$f")"
done

You can use sed to add a space between adjacent parentheses:

for f in *.zip; do
  mv "$f" "$(sed 's/)(/ /g' <<< "$f" | tr -cd 'A-Za-z0-9. \n'))"
done

And you can use sed to merge multiple spaces.

for f in *.zip; do
  mv "$f" "$(sed 's/)(/ /g' <<< "$f" | tr -cd 'A-Za-z0-9. \n' | sed 's/ \ / /g'))"
done

CodePudding user response:

I assume that when you write "Filenames should only have chars A-Z & 1-9" you include lower case letters.

Let's first write a small bash script file that takes the path of a zip file as first an only parameter ($1), separates the directory ($d) and file ($f) parts with dirname and basename, computes the new file name with tr and cut, and renames the file:

$ cat /mnt/Beers4TB/opendirs/TDC19/renamer.sh
#!/usr/bin/env bash
d="$(dirname "$1")"
f="$(basename -s .zip "$1" | tr -dc a-zA-Z1-9 | cut -c 1-76)"
mv "$1" "$d/$f.zip"

Next, let's make the script executable (chmod) and use find to walk the hierarchy and call the script on each found zip file (first backup your files, just in case something goes wrong):

$ cd /mnt/Beers4TB/opendirs/TDC19
$ chmod  x renamer.sh
$ find . -type f -name '*.zip' -exec ./renamer.sh '{}' \;

(in the exec action of find {} is replaced by the found file path).

Explanations:

  • tr is used to remove all unwanted characters. Option -d deletes the specified characters, and option -c takes the complement of the specified character set:

      $ f='Mean 18 - Golf Menu [SW] (1988)(Robert J. Butler) [Sports, Golf, Utility]'
      $ printf '%s' "$f" | tr -dc a-zA-Z1-9
      Mean18GolfMenuSW1988RobertJButlerSportsGolfUtility
    
  • cut is used to clip the modified base name to 80-4=76 characters. After restoring the .zip suffix it will have 80 characters at most. The -c X-Y option of cut selects characters number X to Y:

      $ f='abcdefghi'
      $ printf '%s' "$f" | cut -c 1-4
      abcd
    

CodePudding user response:

Using a while read loop, Process Substitution and find plus mv to rename the files.


The script.

#!/usr/bin/env bash

shopt -s extglob nullglob

while IFS= read -rd '' directory; do
  if [[ -e $directory && -x $directory ]] ; then
    (
      printf 'Entering directory %s\n' "$directory"
      cd "$directory" || exit
      files=(*.zip)
      (( ${#files[*]} )) || {
        printf 'There are no files ending in *.zip here!, moving on...\n'
        continue
      }
      for file_name_with_extension in *.zip; do
        extension=${file_name_with_extension##*.}
        file_name_without_extension=${file_name_with_extension%."$extension"}
        change_spaces_to_underscore="${file_name_without_extension// ([[:space:]])/_}"
        remove_everything_that_is_not_alnum_and_under_score="${change_spaces_to_underscore//[![:alnum:]_]}"
        change_every_underscore_with_a_single_under_score="${remove_everything_that_is_not_alnum_and_under_score// (_)/_}"
        new_file_name="$change_every_underscore_with_a_single_under_score.$extension"
        mv -v "$file_name_with_extension" "${new_file_name::80}"
      done
    )
  fi
done < <(find . ! -name . -type d -print0)

The script for creating dummy directories and files.

#!/usr/bin/env bash

mkdir -p foo/bar/baz/more/qux/sux

cd foo/ &&  touch 'Mean 18 - Golf Menu [SW] (1988)(Robert J. Butler) [Sports, Golf, Utility].zip'
cd bar/ &&  touch 'Mean 18 - M18 (1988)(Ken Hopkins) [Sports, Golf, Utility].zip'
cd baz/ && touch 'Metaltech- Battledrome Game Editor (1994)(Sierra On-Line, Inc.) [Utility].mp4'
cd more/ && touch 'Might and Magic III Character Editor (1991)(Blackbeard'\''s Ghost) [Utility].zip'
cd qux/ && touch 'Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].zip'
cd sux/ && touch 'Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].jpg'

Checking the directory tree with tree

tree foo/
foo/
├── bar
│   ├── baz
│   │   ├── Metaltech- Battledrome Game Editor (1994)(Sierra On-Line, Inc.) [Utility].mp4
│   │   └── more
│   │       ├── Might and Magic III Character Editor (1991)(Blackbeard's Ghost) [Utility].zip
│   │       └── qux
│   │           ├── Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].zip
│   │           └── sux
│   │               └── Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].jpg
│   └── Mean 18 - M18 (1988)(Ken Hopkins) [Sports, Golf, Utility].zip
└── Mean 18 - Golf Menu [SW] (1988)(Robert J. Butler) [Sports, Golf, Utility].zip

5 directories, 6 files

Using find to print the files.

find foo/ ! -name . -type f 

The output is

foo/Mean 18 - Golf Menu [SW] (1988)(Robert J. Butler) [Sports, Golf, Utility].zip
foo/bar/Mean 18 - M18 (1988)(Ken Hopkins) [Sports, Golf, Utility].zip
foo/bar/baz/more/Might and Magic III Character Editor (1991)(Blackbeard's Ghost) [Utility].zip
foo/bar/baz/more/qux/sux/Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].jpg
foo/bar/baz/more/qux/Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].zip
foo/bar/baz/Metaltech- Battledrome Game Editor (1994)(Sierra On-Line, Inc.) [Utility].mp4

Running the script inside the top level directory print something like:

Entering directory ./foo
mv -v Mean 18 - Golf Menu [SW] (1988)(Robert J. Butler) [Sports, Golf, Utility].zip Mean_18_Golf_Menu_SW_1988Robert_J_Butler_Sports_Golf_Utility.zip
Entering directory ./foo/bar
mv -v Mean 18 - M18 (1988)(Ken Hopkins) [Sports, Golf, Utility].zip Mean_18_M18_1988Ken_Hopkins_Sports_Golf_Utility.zip
Entering directory ./foo/bar/baz
There are no files ending in *.zip here!, moving on...
Entering directory ./foo/bar/baz/more
mv -v Might and Magic III Character Editor (1991)(Blackbeard's Ghost) [Utility].zip Might_and_Magic_III_Character_Editor_1991Blackbeards_Ghost_Utility.zip
Entering directory ./foo/bar/baz/more/qux
mv -v Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].zip Might_Magic_3_Character_viewereditor_v11_1991Mark_Betz_and_Chris_Lampton_Editor.
Entering directory ./foo/bar/baz/more/qux/sux
There are no files ending in *.zip here!, moving on...

  • Remove the echo if you're satisfied with the output in order for mv to rename the files.

Without the echo the output is something like:

Entering directory ./foo
renamed 'Mean 18 - Golf Menu [SW] (1988)(Robert J. Butler) [Sports, Golf, Utility].zip' -> 'Mean_18_Golf_Menu_SW_1988Robert_J_Butler_Sports_Golf_Utility.zip'
Entering directory ./foo/bar
renamed 'Mean 18 - M18 (1988)(Ken Hopkins) [Sports, Golf, Utility].zip' -> 'Mean_18_M18_1988Ken_Hopkins_Sports_Golf_Utility.zip'
Entering directory ./foo/bar/baz
There are no files ending in *.zip here!, moving on...
Entering directory ./foo/bar/baz/more
renamed 'Might and Magic III Character Editor (1991)(Blackbeard'\''s Ghost) [Utility].zip' -> 'Might_and_Magic_III_Character_Editor_1991Blackbeards_Ghost_Utility.zip'
Entering directory ./foo/bar/baz/more/qux
renamed 'Might Magic 3 Character viewer-editor v1.1 (1991)(Mark Betz and Chris Lampton) [Editor].zip' -> 'Might_Magic_3_Character_viewereditor_v11_1991Mark_Betz_and_Chris_Lampton_Editor.'
Entering directory ./foo/bar/baz/more/qux/sux
There are no files ending in *.zip here!, moving on...

  • Related