2

Hello ALL and thanks in advance.

I have searched the forum for my situation and have been unable to locate a solution. I've got a script that I am passing arguments/options/parameters to at the command line. One of the values has a space in it, which I have put in double quotes. It might be easier to provide an example. Forgive my usage of arguments/options/parameters.

$:  ./test1.ksh -n -b -d "Home Videos"

My problem is setting a variable to "Home Videos" and it being used together. In my example, the -d is to specify a directory. Not all the directories have spaces, but some do in my case.

This is an example of the code I have that is not working as I expect it to.

#!/bin/ksh

Function1()
{
echo "Number of Args in Function1: $#"
echo "Function1 Args: $@"
SetArgs $*
}

SetArgs()
{
echo -e "\nNumber of Args in SetArgs: $#"
echo "SetArgs Args: $@"
while [ $# -gt 0 ]
do
  case $1 in
    -[dD])
    shift
    export DirectoryName=$1
    ;;
    -[nN])
    export Var1=No
    shift
    ;;
    -[bB])
    export Var2=Backup
    shift
    ;;
    *)
    shift
    ;;
  esac
done
Function2
}

Function2()
{
echo "Directory Name: ${DirectoryName}"
}

Function1 $*

When I run this, I'm getting only Home for the DirectoryName instead of Home Videos. Seen below.

 $ ./test1.ksh -n -b -d "Home Videos"
 Number of Args in Function1: 5
 Function1 Args: -n -b -d Home Videos

 Number of Args in SetArgs: 5
 SetArgs Args: -n -b -d Home Videos
 Var1 is set to:  No
 Var2 is set to:  Backup
 Directory Name: Home

What I am expecting and I have not been able to get it to happen is:

 $ ./test1.ksh -n -b -d "Home Videos"
 Number of Args in Function1: 4
 Function1 Args: -n -b -d "Home Videos"

 Number of Args in SetArgs: 4
 SetArgs Args: -n -b -d "Home Videos"
 Var1 is set to:  No
 Var2 is set to:  Backup
 Directory Name: Home Videos     <-- Without double quotes in the final usage.

Any help I can get on this will be greatly appreciated... I've tried escaping the double quotes, without any success.

Thank you for your time and efforts in helping me figure this out.

Regards, Daniel

2 Answers 2

4

Using $* or $@ unquoted never makes sense.

"$*" is the concatenation of the positional parameters with the first character (or byte depending on the shell) of $IFS, "$@" is the list of positional parameters.

When unquoted, it's the same but subject to split+glob (or only empty removal with zsh) like any other unquoted parameter expansion, (some shells do also separate arguments in $* even if $IFS is empty).

Here you want to pass the list of arguments as-is to your function, so it's:

SetArgs "$@"
[...]
Function1 "$@"

Note that with ksh88, $IFS has to contain the space character (which it does by default) for that to work properly (a bug inherited from the Bourne shell, fixed in ksh93).

Also note that with some implementations of ksh (like older versions of zsh in ksh emulation),

export DirectoryName=$1

is a split+glob invocation case. export is one of those commands in Korn-like shells that can evaluate shell code through arithmetic evaluation in array indices), so it's one of those cases where it's important to quote variables to avoid introducing command injection vulnerabilities.

Example:

$ (exec -a ksh zsh-4.0.1 -c 'export x=$a' ksh 'foo psvar[0`uname>&2`]')
Linux

Note that [ $# -gt 0 ] is another split+glob invocation which doesn't make sense (less likely to be a problem at least with the default value of $IFS).

3
  • I knew it would be something simple, I tried every but what worked... I had tried to use "$*", but that was being read as a single argument.. $# was 1. I replaced the $* with "$@" and that worked...
    – DNadler
    Nov 22, 2017 at 10:34
  • I'm also going to keep the test of $# -gt 0 syntax... I've never had a problem, but if I run into something down the road, I'll take it into consideration. My next step is to re-write this in C++. I've written common language for a long time, no pro by any means, and am looking to update many of my ash programs to C or C++. Thank you very much Stéphane Chazelas!
    – DNadler
    Nov 22, 2017 at 10:37
  • @DNadler, you may also want to consider the standard getopts utility for parsing command line options. Note that there is no drawback to writing [ "$#" -gt 0 ]. On the other hand, [ $# -gt 0 ] stops working in contexts where $IFS contains digits. I recommend reading Security implications of forgetting to quote a variable in bash/POSIX shells Nov 22, 2017 at 10:42
0

Have you considered using the getopts builtin shell command, to parse your arguments (as suggested e.g. by @Stéphane Chazelas in this comment)? That would save you much of this hassle.

In your case, the relevant code would look as follows:

while getopts "nbd:" argname
do
    case "$argname" in
    n)  Var1="No" ;;
    b)  Var2="Backup" ;;
    d)  DirectoryName ="$OPTARG" ;;
    ?)  echo -e "usage is..."
        exit 1 ;;
    esac
done

You must log in to answer this question.

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