I am writing a script to rename my files, The current syntax for filename is program 1.c and I want to change this to cprogram-program1.c.

I am unable to get this format. Few conditions for simplicity are:

  • assume that there are only 10 files i.e: 0,1,2,3..9

My procedure to achieve this:

  • First we need to filter the files to find out files that follow the given pattern

  • Then we need to filter the filename into substrings ignorer to verify whether they are in a proper format

  • If they are in a proper format, then we can edit the filename in the way we need it.

I am stuck on step 1 and 2, this is sort of what I am doing:

for fn in *; do --> this loops over the files 
 number=${..} --> number between 0 and 9
 extension=${..} --> gets file extension like .c

if [ "$program" == "program"  ]
    if [ "$number" -ge 0 ] && [ "$number" -le 9 ]

         if [ "$extension" == ".c" ]
            --> edit code 


My problem: I have tried many permutations of the above example, but I am unable to get what I want. Any help, simple method of doing this would be highly appreciated.


  • Do the current filenames really have a space; eg, program 1.c? – jasonwryan Oct 1 '15 at 2:55
  • @jasonwryan yeah there is a space – Mathew Oct 1 '15 at 2:56
  • for file in *.c; do [[( -f $file && $file =~ program )]] && echo cprogram-"${file/ /}"; done – jasonwryan Oct 1 '15 at 3:04
for fn in *
do  case $fn in
        : do something;;
        : do something with this match;;
        : do something with these matches
        : do as many lines as you want;;
    (*) : catch all last default match

A commonly used technique in case statements is to prune unwanted matches with more specific patterns than your generally desired pattern. For example:

for fn in *
do  case $fn in
    (*[0-9][0-9].c) ;;
        echo mv "$fn" "${fn%???}0${fn#"${fn%???}"}"

In the above example the first *[0-9][0-9].c pattern matches all $fn values where two or more digits might occur to the left of the extension. The execution block for those matches is empty - null - nothing at all happens when a match is found. Most importantly, though, because case statements work top-down, what this means is the only results ever matched for the action block will contain only the one digit to the left of the extension, and the example echo command would insert a 0 before each and every one of those occurring between 1 and 8.

| improve this answer | |
  • thanks for the approach, I am having trouble executing the case statement, this example doesn't return anything : for fn in * do case $fn in (*) : echo "hi" ;; esac done – Mathew Oct 1 '15 at 4:07
  • ^ can you please tell me what the issue might be – Mathew Oct 1 '15 at 4:08
  • @Mathew - yeah, of course. The issue is the : null command. I prefixed all of the command statements with : true on purpose - so nothing would happen. It's all a do nothing there, but if you remove your : colon, your command will print hi. – mikeserv Oct 1 '15 at 4:12

Alternatively, dispense with the script and use a rename tool instead.

Frustratingly there are (at least) two different instances of rename depending on your distribution. On some systems the Perl version may be called prename. However, you can tell which one you have by running rename -n ';' /dev/null. If nothing happens you have the Perl version. If you get an error it's the other one.

The current syntax for filename is program 1.c and I want to change this to cprogram-program1.c. Assume that there are only 9 files i.e: 0,1,2,3..9

  1. The Perl-based rename (prename)

    rename 's/^/cprogram-/; s/\s//' program\ ?.c
  2. The other rename

    rename -v 'program ' cprogram-program program\ ?.c
| improve this answer | |

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.