2

Unable to print same argument of $1

    #!/bin/bash
    if [[ "$1" =~ ^((-{1,2})([Hh]$|[Hh][Ee][Ll][Pp])|)$ ]]; then
            display_help; exit 1
    else
            while [[ $# -gt 0 ]]; do
            opt="$1"
            shift;
            current_arg="$1"
            case "$opt" in
                    "run_command"   ) RUN_COMMAND="$1"; shift;;
                    "cmd1"          ) CMD1="$1"; shift;;
                    *                   ) echo "ERROR: Invalid option: \""$opt"\"" >&2
                          exit 1;;
            esac
            done
    fi

    if [[ "$RUN_COMMAND" == "Custom" ]];then
            export command1=`echo $CMD1`
            echo $command1
    else
            echo "Invalid arguments"
    fi

Result output

  ./test_non.sh run_command Custom cmd1 "date|awk '{print \\$1}'"
    date|awk '{print \}'
2
  • 1
    Please edit your question and give us the simplest possible version of your script that reproduces the error. We need something we can copy and run on our own machines.
    – terdon
    Nov 15, 2019 at 10:56
  • How are you setting $opt, for example?
    – terdon
    Nov 15, 2019 at 11:02

2 Answers 2

3

First of all, when you run this:

./script run_command Custom cmd1 "date|awk '{print $1}'"

Because your command is in double quotes, that means it will be expanded by the shell (bash) before calling your script. You can always test these things using set -x:

$ set -x
$ ./script run_command Custom cmd1 "date|awk '{print $1}'"
+ ./script run_command Custom cmd1 'date|awk '\''{print $1}'\'''
date|awk '{print $1}'

The line starting with + shows you the command actually run. As you can see, the $1 has disappeared because $ indicates a shell variable and, since you have everything in double quotes, that is passed to the shell which tries to expand it. Since $1 isn't set, it expands to nothing. Compare it to what happens if you use a variable that is set:

$ foo="bar"
$ ./script run_command Custom cmd1 "date|awk '{print $foo}'"
+ ./script run_command Custom cmd1 'date|awk '\''{print bar}'\'''
date|awk '{print bar}'

As you can see, the $foo in your awk command is expanded to bar before being passed to ./script. So, you need to escape the $1:

$ ./script run_command Custom cmd1 "date|awk '{print \$1}'"
+ ./script run_command Custom cmd1 'date|awk '\''{print $1}'\'''
date|awk '{print $1}'

I also don't understand what this is supposed to be doing:

if [[ "$RUN_COMMAND" == "Custom" ]];then
  export command1=`echo $CMD1`
  echo $command1
else

You don't need export at all, and you don't need to echo one variable to set it as the value of another. All you need there is:

if [[ "$RUN_COMMAND" == "Custom" ]];then
  command1=$CMD1

In fact, you don't need $CMD1 at all. Just set $command1 from the beginning. Here's a slightly improved version of your script:

#!/bin/bash

## dummy function since you didn't include yours
display_help(){
  echo "help"
}

if [[ "$1" =~ ^((-{1,2})([Hh]$|[Hh][Ee][Ll][Pp])|)$ ]]; then
  display_help
  exit 1
else
  while [[ $# -gt 0 ]]; do
    opt="$1"
    shift;
    current_arg="$1"
    case "$opt" in
      "run_command")
        RUN_COMMAND="$1"
        shift
        ;;
      "cmd1")
        command1="$1"
        shift
        ;;
      *)
        echo "ERROR: Invalid option: '$opt'" >&2
        exit 1
        ;;
    esac
  done
fi

if [[ "$RUN_COMMAND" == "Custom" ]];then
  echo "$command1"
else
  echo "Invalid arguments"
fi
0

You should use

./script run_command Custom cmd1 "date|awk '{print \\$1}'"

Why? I don't really know the reason of that double \, but probably it need to escape the special character $ AND the argument number too (one \ for $ and 1)

Here is some results :

  • good one :

    damadam@Pc:~$ export command1=`echo "date|awk '{print \\$1}'"`
    damadam@Pc:~$ echo $command1
    date|awk '{print $1}'
    
  • tests :

    damadam@Pc:~$ export command1=`echo "date|awk '{print \$\1}'"`
    damadam@Pc:~$ echo $command1
    date|awk '{print $\1}'
    
    damadam@Pc:~$ export command1=`echo "date|awk '{print $\1}'"`
    damadam@Pc:~$ echo $command1
    date|awk '{print $\1}'
    
  • OP test :

    damadam@Pc:~$ export command1=`echo "date|awk '{print \$1}'"`
    damadam@Pc:~$ echo $command1
    date|awk '{print }'
    

Edit 1: with the sample script code given by OP (I named it test.sh to test it personnally), just need a single \ to escape the $1 argument

damadam@Pc:~$ ./test.sh run_command Custom cmd1 "date|awk '{print \$1}'"
date|awk '{print $1}'
1
  • 1
    You only needed the two \\ because you were using two levels: first, the process substitution (var1=`echo var2` ), which wasn't needed anyway since you could just do var1=var2. The process substitution runs in a separate subshell, so you needed one escape to pass the $1 correctly to that. Then, the whole thing was in double quotes, so you needed the second escape so that $1 wasn't expanded in the double quotes before even being passed to the first subshell.
    – terdon
    Nov 15, 2019 at 11:18

You must log in to answer this question.

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