It's kind of hard to search for an answer on this since $# doesn't seem to go through properly on search engines. I was curious as to why argv typically includes the command name itself, while $# doesn't.
To make it clearer, if I have a script called testing.sh
#!/bin/bash
echo $#
./testing.sh returns 0 and not 1. Why?
bash is following the POSIX specification for $#:
Expands to the decimal number of positional parameters. The command name (parameter 0) shall not be counted in the number given by '#' because it is a special parameter, not a positional parameter.
The shell's interface to the arguments is simply different from C's. In bash terms, you might define
argv=( "$0" "$#")
argc=${#argv[#]}
since the shell (sensibly) separates the command name from the command's arguments.
Related
This question already has answers here:
Propagate all arguments in a Bash shell script
(12 answers)
Closed 3 years ago.
Let's say I have a function abc() that will handle the logic related to analyzing the arguments passed to my script.
How can I pass all arguments my Bash script has received to abc()? The number of arguments is variable, so I can't just hard-code the arguments passed like this:
abc $1 $2 $3 $4
Better yet, is there any way for my function to have access to the script arguments' variables?
The $# variable expands to all command-line parameters separated by spaces. Here is an example.
abc "$#"
When using $#, you should (almost) always put it in double-quotes to avoid misparsing of arguments containing spaces or wildcards (see below). This works for multiple arguments. It is also portable to all POSIX-compliant shells.
It is also worth noting that $0 (generally the script's name or path) is not in $#.
The Bash Reference Manual Special Parameters Section says that $# expands to the positional parameters starting from one. When the expansion occurs within double quotes, each parameter expands to a separate word. That is "$#" is equivalent to "$1" "$2" "$3"....
Passing some arguments:
If you want to pass all but the first arguments, you can first use shift to "consume" the first argument and then pass "$#" to pass the remaining arguments to another command. In Bash (and zsh and ksh, but not in plain POSIX shells like dash), you can do this without messing with the argument list using a variant of array slicing: "${#:3}" will get you the arguments starting with "$3". "${#:3:4}" will get you up to four arguments starting at "$3" (i.e. "$3" "$4" "$5" "$6"), if that many arguments were passed.
Things you probably don't want to do:
"$*" gives all of the arguments stuck together into a single string (separated by spaces, or whatever the first character of $IFS is). This looses the distinction between spaces within arguments and the spaces between arguments, so is generally a bad idea. Although it might be ok for printing the arguments, e.g. echo "$*", provided you don't care about preserving the space within/between distinction.
Assigning the arguments to a regular variable (as in args="$#") mashes all the arguments together like "$*" does. If you want to store the arguments in a variable, use an array with args=("$#") (the parentheses make it an array), and then reference them as e.g. "${args[0]}" etc. Note that in Bash and ksh, array indexes start at 0, so $1 will be in args[0], etc. zsh, on the other hand, starts array indexes at 1, so $1 will be in args[1]. And more basic shells like dash don't have arrays at all.
Leaving off the double-quotes, with either $# or $*, will try to split each argument up into separate words (based on whitespace or whatever's in $IFS), and also try to expand anything that looks like a filename wildcard into a list of matching filenames. This can have really weird effects, and should almost always be avoided. (Except in zsh, where this expansion doesn't take place by default.)
I needed a variation on this, which I expect will be useful to others:
function diffs() {
diff "${#:3}" <(sort "$1") <(sort "$2")
}
The "${#:3}" part means all the members of the array starting at 3. So this function implements a sorted diff by passing the first two arguments to diff through sort and then passing all other arguments to diff, so you can call it similarly to diff:
diffs file1 file2 [other diff args, e.g. -y]
Use the $# variable, which expands to all command-line parameters separated by spaces.
abc "$#"
Here's a simple script:
#!/bin/bash
args=("$#")
echo Number of arguments: $#
echo 1st argument: ${args[0]}
echo 2nd argument: ${args[1]}
$# is the number of arguments received by the script. I find easier to access them using an array: the args=("$#") line puts all the arguments in the args array. To access them use ${args[index]}.
It's worth mentioning that you can specify argument ranges with this syntax.
function example() {
echo "line1 ${#:1:1}"; #First argument
echo "line2 ${#:2:1}"; #Second argument
echo "line3 ${#:3}"; #Third argument onwards
}
I hadn't seen it mentioned.
abc "$#" is generally the correct answer.
But I was trying to pass a parameter through to an su command, and no amount of quoting could stop the error su: unrecognized option '--myoption'. What actually worked for me was passing all the arguments as a single string :
abc "$*"
My exact case (I'm sure someone else needs this) was in my .bashrc
# run all aws commands as Jenkins user
aws ()
{
sudo su jenkins -c "aws $*"
}
abc "$#"
$# represents all the parameters given to your bash script.
I basically want to do bash -c "$#", but that doesn't work (my command does not get run). While eval "$#" works fine, what's the difference?
I want to do something like this:
myscript:
function run_it() {
bash -c "$#"
}
run_it $#
./myscript MY_VAR=5 make my-target
It's because of the quoting. This should work better:
function run_it() {
bash -c "$*" # Change 1
}
run_it "$#" # Change 2
The reason for change 1: $# is special when used inside quotes, like "$#". Rather than expanding to a single argument, it expands to a series of quoted arguments: "MY_VAR=5" "make" "my-target". As a result, the -c flag only receives the MY_VAR=5 part, which is executed with make and my-target as arguments $0 and $1 respectively. By using "$*" you do end up with a single string. Note that this still doesn't handle spaces correctly; not sure how to fix that.
The reason for change 2: Here we do want every argument to be quoted individually. This makes sure that arguments aren't being split too soon. It might be pointless until you fix the other spaces issue first though.
I am trying to modify a shell script that isn't very well documented. I know the basics, but this snippet is confusing.
I am not sure what this line does:
time java -showversion -jar ${here_dir}/AESampleTool.jar -f $FILES -d ${output_dir} $*
I don't know what $* is. Google doesn't have much. Does the above line set $* equal to what is before it? The next line in the script is $* is passed as a parameter to a function called launch:
launch $* 1>$log_file 2>&1
Below is the function. The weird part is it seems to be a circular reference. inside the function is what sets $* but then that is passed as a parameter to the function itself.
function launch {
hset -x
USER=$AEX_USER
l_output_dir=$output_dir
l_here_dir=$here_dir
l_LOGFILE=$LOGFILE
l_FILES=$FILES
l_EXE_JAR=$EXE_SH
l_AEX_LOGDIR=$AEX_LOGDIR
l_AEX_LOGNAME=$AEX_LOGNAME
time java -showversion -jar ${here_dir}/AESampleTool.jar -f $FILES -d ${output_dir} $*
rc=$?
}
$* means all arguments, but it's the wrong way to pass them on because it will either split them on whitespace if unquoted (like here) or combine them into a single argument if quoted. It's better to use "$#", which will pass them along in a whitespace-safe manner.
$*, and $# are all related to all the arguments to the shell, but they do different things.
When unquoted, $* and $# do the same thing. They treat each word (sequence of non-whitespace) as a separate argument.
When quoted they are quite different. "$*" treats the argument list as a single space-separated string, whereas "$#" treats the arguments almost exactly as they were when specified on the command line.
What does $* mean in bash scripting?
I tried to search on google for it, but I found only about $0, $1 and so on.
From the man page:
* Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, it expands to a single
word with the value of each parameter separated by the first character of the IFS special variable. That is, "$*" is equivalent
to "$1c$2c...", where c is the first character of the value of the IFS variable. If IFS is unset, the parameters are separated
by spaces. If IFS is null, the parameters are joined without intervening separators.
So it is equivalent to all the positional parameters, with slightly different semantics depending on whether or not it is in quotes.
See this page:
http://tldp.org/LDP/abs/html/internalvariables.html#IFSEMPTY
The behavior of $* and $# when $IFS is empty depends
+ on which Bash or sh version being run.
It is therefore inadvisable to depend on this "feature" in a script.
It's all the arguments passed to the script, except split by word. You almost always want to use "$#" instead. And it's all in the bash(1) man page.
Its the list of arguments supplied on the command line to the script .$0 will be the script name.
It's a space separated string of all arguments. For example, if $1 is "hello" and $2 is "world", then $* is "hello world". (Unless $IFS is set; then it's an $IFS separated string.)
You can use symbolhound search engine to find codes that google will not look for.
For your query click here
If you see $ in prefix with anything , it means its a variable. The value of the variable is used.
Example:
count=100
echo $count
echo "Count Value = $count"
Output of the above script:
100
Count Value = 100
As an independent command it doesn't have any significance in bash scripting.
But, as per usage in commands, it's used to indicate common operation on files / folders with some common traits.
and with grep used to represent zero or more common traits in a command.
This question already has answers here:
Propagate all arguments in a Bash shell script
(12 answers)
Closed 3 years ago.
Let's say I have a function abc() that will handle the logic related to analyzing the arguments passed to my script.
How can I pass all arguments my Bash script has received to abc()? The number of arguments is variable, so I can't just hard-code the arguments passed like this:
abc $1 $2 $3 $4
Better yet, is there any way for my function to have access to the script arguments' variables?
The $# variable expands to all command-line parameters separated by spaces. Here is an example.
abc "$#"
When using $#, you should (almost) always put it in double-quotes to avoid misparsing of arguments containing spaces or wildcards (see below). This works for multiple arguments. It is also portable to all POSIX-compliant shells.
It is also worth noting that $0 (generally the script's name or path) is not in $#.
The Bash Reference Manual Special Parameters Section says that $# expands to the positional parameters starting from one. When the expansion occurs within double quotes, each parameter expands to a separate word. That is "$#" is equivalent to "$1" "$2" "$3"....
Passing some arguments:
If you want to pass all but the first arguments, you can first use shift to "consume" the first argument and then pass "$#" to pass the remaining arguments to another command. In Bash (and zsh and ksh, but not in plain POSIX shells like dash), you can do this without messing with the argument list using a variant of array slicing: "${#:3}" will get you the arguments starting with "$3". "${#:3:4}" will get you up to four arguments starting at "$3" (i.e. "$3" "$4" "$5" "$6"), if that many arguments were passed.
Things you probably don't want to do:
"$*" gives all of the arguments stuck together into a single string (separated by spaces, or whatever the first character of $IFS is). This looses the distinction between spaces within arguments and the spaces between arguments, so is generally a bad idea. Although it might be ok for printing the arguments, e.g. echo "$*", provided you don't care about preserving the space within/between distinction.
Assigning the arguments to a regular variable (as in args="$#") mashes all the arguments together like "$*" does. If you want to store the arguments in a variable, use an array with args=("$#") (the parentheses make it an array), and then reference them as e.g. "${args[0]}" etc. Note that in Bash and ksh, array indexes start at 0, so $1 will be in args[0], etc. zsh, on the other hand, starts array indexes at 1, so $1 will be in args[1]. And more basic shells like dash don't have arrays at all.
Leaving off the double-quotes, with either $# or $*, will try to split each argument up into separate words (based on whitespace or whatever's in $IFS), and also try to expand anything that looks like a filename wildcard into a list of matching filenames. This can have really weird effects, and should almost always be avoided. (Except in zsh, where this expansion doesn't take place by default.)
I needed a variation on this, which I expect will be useful to others:
function diffs() {
diff "${#:3}" <(sort "$1") <(sort "$2")
}
The "${#:3}" part means all the members of the array starting at 3. So this function implements a sorted diff by passing the first two arguments to diff through sort and then passing all other arguments to diff, so you can call it similarly to diff:
diffs file1 file2 [other diff args, e.g. -y]
Use the $# variable, which expands to all command-line parameters separated by spaces.
abc "$#"
Here's a simple script:
#!/bin/bash
args=("$#")
echo Number of arguments: $#
echo 1st argument: ${args[0]}
echo 2nd argument: ${args[1]}
$# is the number of arguments received by the script. I find easier to access them using an array: the args=("$#") line puts all the arguments in the args array. To access them use ${args[index]}.
It's worth mentioning that you can specify argument ranges with this syntax.
function example() {
echo "line1 ${#:1:1}"; #First argument
echo "line2 ${#:2:1}"; #Second argument
echo "line3 ${#:3}"; #Third argument onwards
}
I hadn't seen it mentioned.
abc "$#" is generally the correct answer.
But I was trying to pass a parameter through to an su command, and no amount of quoting could stop the error su: unrecognized option '--myoption'. What actually worked for me was passing all the arguments as a single string :
abc "$*"
My exact case (I'm sure someone else needs this) was in my .bashrc
# run all aws commands as Jenkins user
aws ()
{
sudo su jenkins -c "aws $*"
}
abc "$#"
$# represents all the parameters given to your bash script.