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
