I am trying to understand what a parameter expansion does inside a bash script.
third_party_bash_script
#!/bin/sh
files="${*:--}"
# For my understanding I tried to print the contents of files
echo $files
pkill bb_stream
if [ "x$VERBOSE" != "" ]; then
ARGS=-v1
fi
while [ 1 ]; do cat $files; done | bb_stream $ARGS
When I run ./third_party_bash_script
, all it prints is a hyphen -
and nothing else. Since it did not make sense to me, I also tried to experiment with it in the terminal
$ set one="1" two="2" three="3"
$ files="${*:--}"
$ echo $files
one="1" two="2" three="3"
$ set four="4"
$ files="${*:--}"
four="4"
I can't seem to understand what it's doing. Could someone kindly help me with the interpretation of ${*:--}
by the sh
?
CodePudding user response:
"$@"
is an array of the arguments passed to your script, "$*"
is a string of all of those arguments concatenated with blanks in between.
"${*:--}"
is the string of arguments if any were provided (:-
), or -
otherwise which means "take input from stdin" otherwise.
"${@:--}"
is the array of arguments if any were provided (:-
), or -
otherwise which means "take input from stdin" otherwise.
$ cat file
foo
bar
$ cat tst.sh
#!/usr/bin/env bash
awk '{ print FILENAME, $0 }' "${@:--}"
When an arg is provided to the script, "$@"
contains "file"
so that is the arg that awk is called with:
$ ./tst.sh file
file foo
file bar
When no arg is provided to the script, "$@"
is empty so awk is called with -
(meaning read from stdin) as it's arg:
$ cat file | ./tst.sh
- foo
- bar
You almost always want to use "${@:--}"
rather than "${*:--}"
in this context, see https://unix.stackexchange.com/questions/41571/what-is-the-difference-between-and for more info on "$@"
vs "$*"
.
CodePudding user response:
${param:-default}
expands to the value of $param
if $param
is set and not empty, otherwise it expands to default
.
$*
is all the command-line arguments to the script.
In ${*:--}
, param
is *
and default
is -
. If $*
is not an empty string, it expands to the script arguments. If it's empty, it expands to the default value -
.
This can be used in a script to implement the common behavior that a program reads from the files listed in its arguments, and reads from standard input if no filename arguments are given. Many commands treat an input filename argument -
as standing for the standard input.
CodePudding user response:
NOTE: addressing OP's original, pre-edited post ...
See shell parameter expansion for a brief review of different options.
While the other answers reference the use of ${*:--}
(and ${@:--}
) as a alternate means of reading from stdin, OP's sample script is a bit simpler ... if the variable $*
(ie, script's command line args) is empty then replace with the literal string -
.
We can see this with a few examples:
$ third_party_bash_script
-
$ third_party_bash_script a b c
a b c
$ echo 'a b c' | third_party_bash_script
-
If we replace ${*:--}
with ${*:-REPLACEMENT}
:
$ third_party_bash_script
REPLACEMENT
$ third_party_bash_script a b c
a b c
$ echo 'a b c' | third_party_bash_script
REPLACEMENT
I'm guessing in OP's actual script there's more going on with the $files
variable so in order to know for sure how the ${*:--}
is being processed we'd need to see the actual script and how it's referencing the $files
variable.
As for OP's set|files=|echo
code snippets:
$ set one="1" two="2" three="3"
$ files="${*:--}"
$ echo $files
one=1 two=2 three=3
We can see the same behavior from the script with:
$ third_party_bash_script one="1" two="2" three="3"
one=1 two=2 three=3