Setting an Argument With Bash

How to write a bash script that takes optional input arguments?

You could use the default-value syntax:

somecommand ${1:-foo}

The above will, as described in Bash Reference Manual - 3.5.3 Shell Parameter Expansion [emphasis mine]:

If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.

If you only want to substitute a default value if the parameter is unset (but not if it's null, e.g. not if it's an empty string), use this syntax instead:

somecommand ${1-foo}

Again from Bash Reference Manual - 3.5.3 Shell Parameter Expansion:

Omitting the colon results in a test only for a parameter that is unset. Put another way, if the colon is included, the operator tests for both parameter’s existence and that its value is not null; if the colon is omitted, the operator tests only for existence.

How to change a command line argument in Bash?

You have to reset all arguments. To change e.g. $3:

$ set -- "${@:1:2}" "new" "${@:4}"

Basically you set all arguments to their current values, except for the one(s) that you want to change. set -- is also specified by POSIX 7.

The "${@:1:2}" notation is expanded to the two (hence the 2 in the notation) positional arguments starting from offset 1 (i.e. $1). It is a shorthand for "$1" "$2" in this case, but it is much more useful when you want to replace e.g. "${17}".

Bash: How to set a variable from argument, and with a default value

I see several questions here.

  1. “Can I write something that actually reflects this logic”

    Yes. There are a few ways you can do it. Here's one:

    if [[ "$1" != "" ]]; then
    DIR="$1"
    else
    DIR=.
    fi
  2. “What is the difference between this and DIR=${1-.}?”

    The syntax ${1-.} expands to . if $1 is unset, but expands like $1 if $1 is set—even if $1 is set to the empty string.

    The syntax ${1:-.} expands to . if $1 is unset or is set to the empty string. It expands like $1 only if $1 is set to something other than the empty string.

  3. “Why can't I do this? DIR="$1" || '.'

    Because this is bash, not perl or ruby or some other language. (Pardon my snideness.)

    In bash, || separates entire commands (technically it separates pipelines). It doesn't separate expressions.

    So DIR="$1" || '.' means “execute DIR="$1", and if that exits with a non-zero exit code, execute '.'”.

Setting an argument with bash

The problem is that quotes are not processed after variable substitution. So it looks like you're trying to define a macro named '_transaction_color.

Try using an array:

INSTALL_OPT=(-Uvh --define '_transaction_color 3')

then:

"$INSTALL_CMD" "${INSTALL_OPT[@]}" myPackage.rpm

It's important to put ${INSTALL_OPT[@]} inside double quotes to get the requoting.

Shell how to make some of the script arguments mandatory

I made this work by checking that the variables req and out have some value after the for loop with the below code:

  if [[ -z $out  ||  -z $req ]]
then
echo "ERROR: -q and -o are mandatory arguments. See usage: \n";
exit 1;
fi

Optional arguments in Bash script

I am not sure I understood the question correctly, sorry if I don't answer it...

You could use (for example) getopt(1), as below, which will allow -x option to be anywhere.
Please note that optional arguments (man_arg*) can also be anywhere.

#! /usr/bin/bash

# CMD is the shell-script name without directory (basename)
CMD="${0##*/}"

my_function() {
# Some comments added per OP request

# below variable is used by getopt's "-o" option (short options).
# each letter is a possible option; colon following a letter means this
# option will take a parameter. See getopt(1) for more details.
SOPTS="n:o:x:"

# output of getopt is assigned to TMP. For example, when calling :
# my_function -n n1 a b -o o1 -x x1 c d
# TMP will contain: "-n 'n1' -o 'o1' -x 'x1' -- 'a' 'b' 'c' 'd'"
TMP=$(getopt -o "$SOPTS" -n "$CMD" -- "$@") || exit 1

# assign TMP to positional parameters $1, $2, etc...
eval set -- "$TMP"
unset TMP

while true; do
case "$1" in
-n|-o)
printf "[%s] argument: %s\n" "$1" "$2"
shift
;;
-x)
printf "[-x] argument: %s\n" "$2"
shift
;;
--) # end of options
shift
break
;;

esac
shift
done

nargs=$#
printf "remaining %d args :\n" "$nargs"
for ((i=0; i<nargs; ++i)); do
printf "%d: %s\n" $((i + 1)) "$1"
shift
done
}

my_function "$@"

Examples:

br@lorien:~$ ./test-getopt.bash man_arg1 man_arg2 -n opt_arg1 -o opt_arg2 -x opt_arg3
[-n] argument: opt_arg1
[-o] argument: opt_arg2
[-x] argument: opt_arg3
remaining 2 args :
1: man_arg1
2: man_arg2

br@lorien:~$ ./test-getopt.bash man_arg1 man_arg2 -n opt_arg1 -o opt_arg2 -x opt_arg3 man_arg3 man_arg4
[-n] argument: opt_arg1
[-o] argument: opt_arg2
[-x] argument: opt_arg3
remaining 4 args :
1: man_arg1
2: man_arg2
3: man_arg3
4: man_arg4

br@lorien:~$ ./test-getopt.bash man_arg1 man_arg2 -x opt_arg
[-x] argument: opt_arg
remaining 2 args :
1: man_arg1
2: man_arg2

br@lorien:~$ ./test-getopt.bash -x opt_arg4 man_arg2 -n opt_arg1 -x opt_arg3 man_arg3 man_arg4
[-x] argument: opt_arg4
[-n] argument: opt_arg1
[-x] argument: opt_arg3
remaining 3 args :
1: man_arg2
2: man_arg3
3: man_arg4

EDIT: Rewrote the code into a function, as asked in question.

passing command as argument in bash

You need to quote the pipe when invoking the script. Otherwise the shell will arrange for the standard output your script to be sent standard input of ls and you will end up with the output as if you hand run ls on it's own. Either of these would do:

./simple.sh \|ls
./simple.sh '|ls'
./simple.sh "|ls"


Related Topics



Leave a reply



Submit