-1

I want to add the third parameter that will be changing files name from upper to lower OR lower to upper but in this third parameter I want to specify what file's name must be changed? What's wrong with this script? Thank you in advance.

#!/bin/bash

if test "$1" = "lower" && test "$2" = "upper"
then
    for file in *; do
        if [ $0 != "$file" ] && [ $0 != "./$file" ]; then
        mv "$file" "$(echo $file | tr [:lower:] [:upper:])";
        fi
fi
done

elif test "$1" = "upper" && test "$2" = "lower"
then
    for file in *; do
    if [ $0 != "$file" ] && [ $0 != "./$file" ]; then
    mv "$file" "$(echo $file | tr [:upper:] [:lower:])";
    fi
done
fi

if [ "$1" = "lower" ] && [ "$2" = "upper" ] && [ "$3" = "$file" ]; 
then
    for file in * ; do
    if [ $0 != "$file" ] && [ $0 != "./$file" ]; then
    mv "$file" "$(echo $file | tr [:lower:] [:upper:])";
    fi
done
fi
jww
  • 97,681
  • 90
  • 411
  • 885
versaces
  • 137
  • 6
  • The indentation, for a start. Could you fix it so it's legible? – tripleee Nov 23 '18 at 09:26
  • What do you hope for the comparison against `$0` to actually accomplish? – tripleee Nov 23 '18 at 09:27
  • You should use double quotes around variables which contain file names, everywhere; and the arguments to `tr` should probably be in single quotes. – tripleee Nov 23 '18 at 09:28
  • What's wrong in this script? At least this line: `if [ "$1" = "lower" ] && [ "$2" = "upper" ] && [ "$3" = "$file" ]; then`. The `$file` variable will contain the last file name, that was processed in first `if` block, and it's not guaranteed in any way that it will be exactly the same file as in `$3`. (Even if it is in the current directory, it could've been processed at the beginning or in the middle of the `for` loop in first `if` block). – Yoory N. Nov 23 '18 at 09:36
  • Start by writing a "usage screen" that explains the expected inputs and output. That usually helps me figure out how I want to write the code. – Paul Hodges Nov 23 '18 at 14:32
  • [What are the special dollar sign shell variables?](https://stackoverflow.com/q/5163144/608639). – jww Nov 23 '18 at 17:52

3 Answers3

0

If I am guessing correctly what you want, try

#!/bin/bash

case $1:$2 in
 upper:lower | lower:upper ) ;;
 *) echo "Syntax: $0 upper|lower lower|upper files ..." >&2; exit 1;;
esac

from=$1
to=$2
shift; shift
for file; do
    mv "$file" "$(echo "$file" | tr "[:$from:]" "[:$to:]")"
done

This has the distinct advantage that it allows more than three arguments, where the first two specify the operation to perform.

Notice also how we take care to always quote strings which contain a file name. See also When to wrap quotes around a shell variable?

The above script should in fact also work with /bin/sh; we do not use any Bash-only features so it should run under any POSIX sh.

However, a much better design would probably be to use an option to decide what mapping to apply, and simply accept a (possibly empty) list of options and a list of file name arguments. Then you can use Bash built-in parameter expansion, too. Case conversion parameter expansion operations are available in Bash 4 only, though.

#!/bin/bash

op=',,'
# XXX FIXME: do proper option parsing
case $1 in -u) op='^^'; shift;; esac

for file; do
    eval mv "\$file" "\${file$op}"
done

This converts to lowercase by default, and switches to uppercase instead if you pass in -u before the file names.

In both of these scripts, we use for file as a shorthand for for file in "$@" i.e. we loop over the (remaining) command-line arguments. Perhaps this is the detail you were looking for.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • I don't think the comparisons against `"$0"` were doing anything useful. If you can explain what they were supposed to accomplish, perhaps we can revisit. – tripleee Nov 23 '18 at 11:28
0

Forgive me if I grossly misunderstand, but I think you may have misunderstood how argument passing works.

The named/numbered arguments represent the values you pass in on the command line in their ordinal positions. Each can theoretically have any value that can by stuck in a string. You don't need a third parameter, just a third value.

Let's try a sample.

#! /bin/env bash

me=${0#*/} # strip the path
use="
   $me { upper | lower } file

   changes the NAME of the file given to be all upper or all lower case.

"
# check for correct arguments
case $# in
2) : exactly 2 arguments passed - this is correct ;;
*) echo "Incorrect usage - $me requires exactly 2 arguments $use" >&2
   exit 1 ;;
esac

declare -l lower action # these variables will downcase anything put in them
declare -u upper        # this one will upcase anything in it
declare newname         # create a target variable with unspecified case

action="$1"             # stored the *lowercased* 1st argument passed as $action
case $action in         # passed argument has been lowercased for simpler checking
upper) upper="$2"       # store *uppercased* 2nd arg.
       newname="$upper" # newname is now uppercase.
       ;;
lower) lower="$2"       # store *lowercased* 2nd arg.
       newname="$lower" # newname is now lowercase.
       ;;
    *) echo "Incorrect usage - $me requires 2nd arg to be 'upper' or 'lower' $use" >&2
       exit 1 ;;
esac

if [[ -e "$2" ]]        # confirm the argument exists
then echo "Renaming $2 -> $newname:"
     ls -l "$2"
     echo " -> "
     mv "$2" "$newname" # rename the file
     ls -l "$newname"
else echo "'$2' does not exist. $use" >&2
     exit 1
fi
Paul Hodges
  • 13,382
  • 1
  • 17
  • 36
  • `$0` is the name (including any pathing info used) of the program as executed. Note that at the top I stripped path info to name the program in a variable for messages throughout. – Paul Hodges Nov 23 '18 at 15:02
-1

First of all there is indentation problem with this script check first if condition done should be coming before fi

Below is the correct.

if test "$1" = "lower" && test "$2" = "upper"
then

  for file in *; do
      if [ $0 != "$file" ] && [ $0 != "./$file" ]; then
      mv "$file" "$(echo $file | tr [:lower:] [:upper:])";
      fi
  done
fi

Secondly the question you asked:

#/bin/bash -xe 

[ $# -ne 3 ] && echo "Usage: {lower} {upper} {fileName} " && exit 1 
if [ "$1" = "lower" ] && [ "$2" = "upper" ] && [ -f "$3" ]; 
then 
  mv "$3" "$(echo $3 | tr [:lower:] [:upper:])"; 
fi 

Hope this helps.

  • I mean that when I write in command line: ./changeFileCase lower upper name_of_file, then only this name of file will be changed from lower to upper. I don't know how to write this in the script. – versaces Nov 23 '18 at 10:23
  • 1
    Check this script -> #/bin/bash -xe [ $# -ne 3 ] && echo "Usage: {lower} {upper} {fileName} " && exit 1 if [ "$1" = "lower" ] && [ "$2" = "upper" ] && [ -f $3 ]; then mv "$3" "$(echo $3 | tr [:lower:] [:upper:])"; fi let me know in case any thing more you needed – saurav omar Nov 23 '18 at 10:31