0

I need help with a script that mv (renames) filenames that are shown with single quotes in ls output or files that require single quotes for file operations. The script will be used to rename all files in a directory. I created a batch of test files using every displayable non-alphanumeric character I can type on my US keyboard (with the exceptions of 'a/b' and 'a'b') to test the script with:

touch 'a~b' 'a`b' 'a!b' 'a@b' 'a#b' 'a$b' 'a%b' 'a^b' 'a&b' 'a*b' 'a(b' 'a)b' 'a-b' 'a_b' 'a+b' 'a=b' 'a{b' 'a}b' 'a[b' 'a]b' 'a|b' 'a\b' 'a:b' 'a;b' 'a"b' 'a<b' 'a>b' 'a,b' 'a.b' 'a?b' 'a b'

So now my test directory contains:

psilo@deb:~/sh$ ls
'a$b'   a#b   'a)b'   a-b   'a<b'   a@b   'a^b'  'a|b'
'a b'   a%b   'a*b'   a.b   'a=b'  'a[b'   a_b    a}b
'a!b'  'a&b'   a+b    a:b   'a>b'  'a\b'  'a`b'   a~b
'a"b'  'a(b'   a,b   'a;b'  'a?b'   a]b    a{b    filenametweak.sh

In addition, I have the personal preference to tr a space to a . and an underscore to a .

My script is:

#!/bin/bash
for file in *; do echo mv "$file" `echo $file | tr ' ' '.' | tr '_' '.' | tr -cd '\043\045\053-\056\060-\072\077\100-\132\135\141-\173\175\176'` ; done

I am attempting to remove all of the characters from the input stream via the tr command (with -c & -d arguments) other than the ASCII octal values that are shown between the single quotes. This should produce an output with my "problem" ASCII characters removed (those that require the filename to be wrapped in single quotes on the ls output above).

I have included the echo command before the mv "$file" in the script to test the output before pulling the trigger.

However, when the script encounters the '?' or '*' characters in the filename, it produces undesirable output:

psilo@deb:~/sh$ ./filenametweak.sh
mv a$b ab
mv a b a.b
mv a!b ab
mv a"b ab
mv a#b a#b
mv a%b a%b
mv a&b ab
mv a(b ab
mv a)b ab
mv a*b ab.a.b.ab.ab.a#b.a%b.ab.ab.ab.ab.a+b.a,b.a-b.a.b.a:[email protected]]b.ab.a.b.ab.a{b.ab.a}b.a~b
mv a+b a+b
mv a,b a,b
mv a-b a-b
mv a.b a.b
mv a:b a:b
mv a;b ab
mv a<b ab
mv a=b ab
mv a>b ab
mv a?b ab.a.b.ab.ab.a#b.a%b.ab.ab.ab.ab.a+b.a,b.a-b.a.b.a:[email protected]]b.ab.a.b.ab.a{b.ab.a}b.a~b
mv a@b a@b
mv a[b ab
mv a\b ab
mv a]b a]b
mv a^b ab
mv a_b a.b
mv a`b ab
mv a{b a{b
mv a|b ab
mv a}b a}b
mv a~b a~b
mv filenametweak.sh filenametweak.sh

How can I resolve the problem when filenames with * or ? are encountered - OR - how can I achieve my mv rename intent in bash via a different and/or better method?

2
  • 1
    The unquoted variable expansion in echo $file will be subject to globbing - see for example When is double-quoting necessary? Commented Oct 14, 2023 at 20:18
  • @steeldriver - Thank you. You are correct. After I wrapped the second $file in double quotes, the globbing issue was solved as the * was indeed filtered. But the conversion of filenames with ? still persists... for file in *; do echo mv "$file" `echo "$file" | tr ' ' '.' | tr '_' '.' | tr -cd '\043\045\053-\056\060-\072\077\100-\132\135\141-\173\175\176' ; done Commented Oct 22, 2023 at 2:15

1 Answer 1

0

I finally had time to revisit this script while working on another project and address the issue with filenames that also contain a question mark.

Here is my script solution to rename all files in the current working directory so that all files are named in such a way that they do not require single or double quotes for file operations:

#!/bin/bash
for file in *; do echo mv "$file" `echo "$file" | tr ' ' '.' | tr '_' '.' | tr -cd '\043\045\053-\056\060-\072\100-\132\141-\173\175\176'` ; done

As stated above, this will tr a space (octal 40) character to a . as well as an underscore (_) to a . - which is my personal preference for linux filenames. Adjust to your preferences.

My intent is to use tr -cd to strip all typed characters that require a filename to be enclosed in single or double quotes for file operations. The exception here is the right/closing bracket (octal 135, ]) which does not require single or double quotes. I chose to eliminate the right/closing bracket for consistency because, interestingly, the left/opening bracket (octal 133, [) does require single or double quotes for file operations.

  • Test the script with:
    ~$ touch 'test~`!@#$%^&*()-_+={}[]|\:;"<>,.? test'
    ~$ ls
    filenametweak.sh 'test~`!@#$%^&*()-_+={}[]|\:;"<>,.? test'
    
  • Run the script.
  • Result:
    ~$ ls
    filenametweak.sh  test~@#%-.+{}:,..test
    

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .