3

I need to elaborate a little bit more. These commands are actually for a BBS FTN tosser. The configuration file for which these commands reside in, only allow specific declarations. Here are a few examples:

exec "/home/imp/imp/poll.sh" *.su? *.mo? *.tu? *.we? *th? *.fr? *.sa? *.pkt
flag toss!.now [0-9a-Z][0-9a-Z][0-9a-Z][0-9a-Z][0-9a-Z][0-9a-Z][0-9a-Z][0-9a-Z].???
exec "/home/imp/imp/poll.sh /home/imp/hpt/secure" /home/imp/hpt/secure/*.[STFWMstfWM][ouaherOUAHER][0-9A-ZA-a] *.[pP][kK][tT]

So that's why I want to use that syntax ([0-9a-z] (for example)). The problem is that the mailer is looking for lowercase filenames, but only uppercase filenames exist.

I'm trying to convert a file from uppercase to lowercase using the syntax below:

mv /home/imp/hpt/outbound/[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z].[STFWMfWM][OUAHER][0-9] /home/imp/hpt/outbound/[0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z].[stfwm][ouaher][0-9a-za-a]

I don't think I have the syntax correct.

Here's an example of a file name I want to rename:

0000FE70.FR0

Any and all help is greatly appreciated. Thanks.

  • In Bash 4: "${file,,}". See the always excellent Wooledge Wiki... – jasonwryan Jul 23 '16 at 3:26
  • Thanks for that.. but i'd like to use the [x-xx-x].. format – ignatius Jul 23 '16 at 3:29
  • 1
    You might be thinking of our friend tr, then... – Jeff Schaller Jul 23 '16 at 3:56
  • Sigh The Wooledge wiki describes exactly how to do that... – jasonwryan Jul 23 '16 at 4:06
  • You can't use [a-Z] as a range! It needs to be [a-zA-Z]. – Kusalananda Jul 23 '16 at 6:48
0

Following worked for me:

    for f in *; do mv -T "$f" "$(echo $f | tr [A-Z] [a-z])"; done

It would be interesting, what the problems are with my solution.

1

Your mv command doesn't work as intended because what happens is that the shell expands the wildcards and the result is a single list of file names which is passed to mv. The syntax of mv is mv SOURCE1 SOURCE2 … DESTINATION, i.e. all the arguments except the last one are file names to be moved to the destination. mv does not support pattern-based renaming.

If you have the prename utility, you can use it to rename files by running Perl code on each name. The syntax is prename PERL-CODE FILENAME1 FILENAME2 …. The file name is in the variable $_, and the function lc converts its argument into lowerecase, so you can use the following code:

prename '$_ = lc($_)' /home/imp/hpt/outbound/[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z].[STFWMfWM][OUAHER][0-9]

If you don't have this utility, you can download a version from CPAN.

Alternatively, you can do the renaming in the shell, with a loop. In bash, you can use ${x,,} to get the value of x converted to lowercase.

for x in /home/imp/hpt/outbound/[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z].[STFWMfWM][OUAHER][0-9]; do
  mv "$x" "${x,,}"
done
1

Here you are:

for i in $( ls | grep [A-Z] ); do mv -f $i `echo $i | tr 'A-Z' 'a-z'`; done

And this is an example showing how it works:

X$ ls

123123HHHSK FILE_[1-10] DB
FILE1       FILE_{1-10} SQL

X$ for i in $( ls | grep [A-Z] ); do mv -f $i `echo $i | tr 'A-Z' 'a-z'`; done

X$ ls

123123hhhsk file_[1-10] db
file1       file_{1-10} sql 

EDIT: We could easily use -f option, to avoid using yes y.

  • 1
    $( ls | grep [A-Z] ) should be the same as the glob *[A-Z]*. If it's not, set LANG=C and try it. – roaima Jul 23 '16 at 12:14
2

With zsh:

autoload zmv # best in ~/.zshrc
zmv '[[:alnum:]](#c8).[STFWMfWM][OUAHER][0-9]' '${(L)f}'

That will take of checking for potential conflicts.

4

Whenever you want to change one class of characters into another, use tr.

for f in *; do
    test -f "$f" && echo mv "$f" "$( tr '[:upper:]' '[:lower:]' <<<"$f" )"
done

The script will rename all files in the current directory to all lowercase letters. It will skip directories. Remove the echo when you're certain it does what you want. You may replace [:upper:] and [:lower:] with A-Z and a-z respectively if you only have standard ASCII filenames (note: A-Z, not [A-Z]).

Alternatively, using Bash's built-in upper-to-lowercase variable substitution:

for f in *; do
    test -f "$f" && echo mv "$f" "${f,,}"
done
  • Hi, can you explain what the <<< does, please? – Daniele Dec 17 '18 at 16:30
  • 1
    @Daniele It's a "here-string". It passes the given string to the standard input of the command. tr '[:upper:]' '[:lower:]' <<<"HELLO" would output hello. It is similar to doing echo 'HELLO' | tr '[:upper:]' '[:lower:]', but without involving echo. Here-strings are an extension to the standard shell syntax, but they are understood by bash. – Kusalananda Dec 17 '18 at 16:39
2

This answer from Alex B at Stack Overflow will help you to rename both files and subfolders under a directory.

It consists on using both find and rename Linux commands. I would only add that the command provided in the link above will modify directory names as well. In case that you want only to change file names, you need to change the -depth option with the next one: -type f.

Another regular expression given to the rename command could be the one below, which I think it is more easy to understand.

 find my_root_dir -type f -execdir rename 'y/A-Z/a-z/' {} \;

Be aware that there is a necessary white space between the rename command regular expression and the curly braces, and another one between them and the command termination character \;

Also remember that it will rename every file not only in the directory where you execute the command from (the my_root_dir directory) but also to all the files under every subfolder contained into this one. You can use the -maxdepth 0 option with the find command to force it to only apply the tests and actions to the starting-points themselves.

  • 1
    note: this is the perl rename, not the util-linux rename. – Jasen Jul 23 '16 at 4:15
  • 1
    I'm not certain that find is needed.. rename 'y/A-Z/a-z/' *[A-Z]* – Jasen Jul 23 '16 at 4:18
  • None of these commands actually work. I keep getting the rename "help screen" :/ – ignatius Jul 23 '16 at 5:04
  • Sorry, I made a mistake with the regular expression in the second command. I also modified the find command -execdir option so it now runs the required action on every directory where a file is found. I tested it and worked. Could you please let me know if it works for you now? – gongomgra Jul 23 '16 at 7:09
1

Simple script rename-lowerfor current dir, if rename command is not working you can change in mv.

#/bin/bash
# script to replace all upper case to lower case
for i in *
do
        d=$(echo ${i} |tr [:upper:] [:lower:]);
        if [ ${d} != ${i} ]
        then
                echo "renaming:" ${i} ${d}
                rename ${i} ${d} ${i}
#               mv ${i} ${d}
        fi
done

Example

$ ls
tmp.EwcM2s6kfU  tmp.kcUX6rtjiu  tmp.kzpqLvWcnQ  tmp.N1H8bLt1at

$ rename-lower
renaming: tmp.EwcM2s6kfU  tmp.ewcm2s6kfu
renaming: tmp.kcUX6rtjiu  tmp.kcux6rtjiu
renaming: tmp.kzpqLvWcnQ  tmp.kzpqlvwcnq
renaming: tmp.N1H8bLt1at  tmp.n1h8blt1at

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.