How Do I Find the Last Positional Parameter in Linux - linux

I am looking to find the last positional parameter. I know to find the number of parameters is $# which logically is the last but I need to find and use what is in the last positional parameter.
It would be like if $# = 5, I want to do $5.
I have tried to do something like $$# or ${$#} as guesses but can't get it.
Instances where I would need to use it is in an if statement or declaring it to another variable or with echo.
I hope that is clear. Thanks in advance.

You want ${!#}, which combines the argument count with indirection.

This seems like a more direct approach:
${#: -1}
Some further information here. I'm not sure about portability outside of Bash.

Here is another way:
while [[ "$1" != "" ]];do
last_parm=$1
shift
done
echo $last_parm
Give a test:
$ ./test.sh 1 2 3 4 5
5

Related

Difference between "${param[0]}" and ${1} in bash

I'm looking at some old scripts and I found some parameter assignment that I have not seen before. A while loop reads from a text file and passes the values to a function. The items in the text file look like this:
user_one:abcdef:secretfolder
the first stage of the function then looks like this:
IFS=':' read -a param <<< $#
user="${param[0]}"
pass="${param[1]}"
user_folders="${param[2]}"
I have not seen this sort of assignment before and was wondering if this is just an alternative way of handling it. Is the above the same as this?
IFS=':' read -a param <<< $#
user="${1}"
pass="${2}"
user_folders="${3}"
(change in values to 1-3 due to ${0} being the name of the file itself). This script is 5 years old; This original sort of assignment just seems a longer way to to it, unless I've missed something
I'm still learning shell scripting but as I understand, setting IFS=':' will split the fields on : rather than whitespace and so in the examples, the value of "${param[0]}" and ${1} passed to the function would be user_one
Can someone please explain if there is a reason why "${param[0]}" should be used instead of ${1}?
The command:
IFS=':' read -a param <<< $#
reads the :-separated fields from the command arguments ($#) into the array variable named param. Bash arrays work just like lists in other languages, and you index them with brackets. ${param[0]} is the first field, ${param[1]} then next, and so on. Arrays like this can contain anything, and it's just because of the $# in the read command that this param array happens to contain the arguments. It could just as easily contain foo, bar, and baz if it were created like:
param=(foo bar baz)
The ${1}, ${2} etc. syntax always refers to the script arguments though.

How can I know if a string contains only one or several words in Bash? [duplicate]

This question already has answers here:
A confusion about ${array[*]} versus ${array[#]} in the context of a bash completion
(2 answers)
Closed 6 years ago.
When I get the content of an array in a string, I have the 2 solutions bellow :
$ a=('one' 'two')
$ str1="${a[*]}" && str2="${a[#]}"
After, of course, I can reuse my string on the code
but how can I know if my variable has only one or several words?
In both cases, the contents of the array are concatenated to a single string and assigned to the variable. The only difference is what is used to join the elements. With ${a[*]}, the first character of IFS is used. With ${a[#]}, a single space is always used.
$ a=(one two)
$ IFS="-"
$ str1="${a[*]}"
$ str2="${a[#]}"
$ echo "$str1"
one-two
$ echo "$str2"
one two
When expanding $str1 or $str2 without quoting, the number of resulting words is entirely dependent on the current value of IFS, regardless of how the variables were originally defined. "$str1" and "$str2" each expand, of course, to a single word.
To add to #chepner's great answer: the difference between ${arr[*]} and ${arr[#]} is very similar to the difference between $* and $#. You may want to refer to this post which talks about $* and $#:
What's the difference between $# and $* in UNIX?
As a rule of thumb, it is always better to use "$#" and "${arr[#]}" than their unquoted or * counterparts.
"${a[*]}" expands to one string for all entries together and "${a[#]}" expands to one string per entry.
Assume we had a program printParameters, which prints for each parameter ($1, $2, and so on) the string my ... parameter is ....
>_ a=('one' 'two')
>_ printParameters "${a[*]}"
my 1. parameter is one two
>_ printParameters "${a[#]}"
my 1. parameter is one
my 2. parameter is two
If you would expand the array manually, you would write
${a[*]} as "one two" and
${a[#]} as "one" "two".
There also differences regarding IFS and so on (see other answers). Usually # is the better option, but * is way faster – use the latter one in cases where you have to deal with large arrays and don't need separate arguments.
By the way: The script printParameters can be written as
#! /bin/bash
argIndex=0
for argValue in "$#"; do
echo "my $((++i)). argument is $argValue"
done
It's very useful for learning more about expansion by try and error.

Use numeric value of input argument in Bash script [duplicate]

This question already has answers here:
Brace expansion with variable? [duplicate]
(6 answers)
Closed 7 years ago.
I would like to use the numeric value of the input argument that I pass to a bash script like this:
./script_pb3.sh out.txt 3
Here I would like to take the second argument that I pass (i.e. the value 3) and use it as a numeric value inside my script, that looks like this:
#!/bin/bash
NUM=$2
for i in {1..$NUM}; do
echo $i
done
But when I run it all I get is
{1..3}
Instead of
1
2
3
Can you please provide an explanation for why this is happening and a workaround? I think that this question aims at casting a string value to an integer value but I am not sure. Any help is greatly appreciated.
EDIT: the answer from here contains a debate concerning the answer to my issue (i.e. it assumes the answer is already known), but it does not come as an answer to my question, therefore I didn't find it in my first searches. Thank you, though, for pointing it out.
I think you have to use seq
for i in `seq 1 10`;
do
echo $i
done
Reference: http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-7.html
So, what you're looking for is : seq 1 $2

bash -declare documentation

If you declare an array like this
declare -a test
you can echo the value like this
i=2
echo ${test[i]}
or
i="1+1"
echo ${test[i]}
why the second form is accepted?
i need a complex answer thanks
See man bash:
The subscript is treated as an arithmetic expression that must evaluate to a number.
Complex enough?

Default values for the arguments to a Unix shell script?

Normally when a parameter is passed to a shell script, the value goes into ${1} for the first parameter, ${2} for the second, etc.
How can I set the default values for these parameters, so that if no parameter is passed to the script, we can use a default value for ${1}?
You can't, but you can assign to a local variable like this: ${parameter:-word} or use the same construct in the place you need $1. this menas use word if _paramater is null or unset
Note, this works in bash, check your shell for the syntax of default values
You could consider:
set -- "${1:-'default for 1'}" "${2:-'default 2'}" "${3:-'default 3'}"
The rest of the script can use $1, $2, $3 without further checking.
Note: this does not work well if you can have an indeterminate list of files at the end of your arguments; it works well when you can have only zero to three arguments.
#!/bin/sh
MY_PARAM=${1:-default}
echo $MY_PARAM
Perhaps I don't understand your question well, yet I would feel inclined to solve the problem in a less sophisticated manner:
! [[ ${1} ]] && declare $1="DEFAULT"
Hope that helps.

Resources