How to remove first bash argument and pass the others to another command? - bash

In bash $# contains all the arguments used to call the script but I am looking for a solution to remove the first one
./wrapper.sh foo bar baz ...:
#!/bin/bash
# call `cmd` with bar baz ... (withouyt foo one)
I just want to call cmd bar baz ...

You can use shift to shift the argument array. For instance, the following code:
#!/bin/bash
echo $#
shift
echo $#
produces, when called with 1 2 3 prints 1 2 3 and then 2 3:
$ ./example.sh 1 2 3
1 2 3
2 3

shift removes arguments from $#.
shift [n]
Shift positional parameters.
Rename the positional parameters $N+1,$N+2 ... to $1,$2 ... If N is
not given, it is assumed to be 1.
Exit Status:
Returns success unless N is negative or greater than $#.

Environment-variable-expansion! Is a very portable solution.
Remove the first argument: with $#
${##"$1"}
Remove the first argument: with $*
${*#"$1"}
Remove the first and second argument: with $#
${##"$1$2"}
Both $# or $* will work because the result of expansion is a string.
links:
Remove a fixed prefix/suffix from a string in Bash
http://www.tldp.org/LDP/abs/html/abs-guide.html#ARGLIST
Variable expansion is portable because it is defined under gnu core-utils
Search for "Environment variable expansion" at this link:
https://www.gnu.org/software/coreutils/manual/html_node/

Related

In bash how to use the last argument- and adding all other arguments to array

I have a script where the user can add as many arguments as he would like (numbers).
The script will sum all the numbers beside the last number - The last number (argument) is the number that I need to divide by
For example:
./test.sh 2 2 6 5
This will sum the first 3 numbers (2+2+6) and divide the answer by 5 (the last argument)
How can I use the last argument? Echo ????
How can I move loop the first arguments besides the last one – I would like that all 3 arguments will be added to an array and I can loop it
Please note that the number of arguments can be changed
How can I use the last argument? Echo ????
Granting $# > 0, you can use "${!#}".
How can I move loop the first arguments besides the last one – I would
like that all 3 arguments will be added to an array and I can loop it
Again granting $# > 0, you can refer to "${#:1:$# - 1}".
Read the Arrays section in the bash manual to know how to properly expand arrays.
I also recommend learning how quoting works and knowing the dangers of unwanted word splitting and globbing.
Shortly (with bashisms)
As this question is tagged integer-arithmetic and bash:
Here is a small and efficient script:
#!/bin/bash
addVals=${*: 1 : $# - 1}
declare -i intResult=" ( ${addVals// /+} ) / ${#: -1} "
echo $intResult
But there's no loop...
Long answer
How can I use the last argument? Echo ????
You could make your tries in command line:
set -- 2 2 6 5
Then
echo $#
2 2 6 5
echo ${*: 3}
6 5
echo ${*: -1}
5
echo ${*: 1 : -1}
bash: -1: substring expression < 0
echo $#
4
echo ${*: 1 : $# -1}
2 2 6
Ok, then
someVar=${*: 1 : $# -1}
echo ${someVar// /:SpaceReplacment:}
2:SpaceReplacment:2:SpaceReplacment:6
so
declare -i result
result=" ( ${someVar// /+} ) / ${*: -1} "
echo $result
2
How can I move loop the first arguments besides the last one – I would like that all 3 arguments will be added to an array and I can loop it
Still forward, under command line...
someArray=("${#: 1: $# -1 }")
Use declare -p to show $someArray's content:
declare -p someArray
declare -a someArray=([0]="2" [1]="2" [2]="6")
Then
declare -i mySum=0
for i in "${someArray[#]}";do
mySum+=i
done
echo $mySum
10
echo $(( mySum / ${*: -1} ))
2
Please note that the number of arguments can be changed
Please note:
Using double quotes allow processing of strings containing spaces:
set -- foo bar 'foo bar baz'
echo ${2}
bar
echo ${*: $# }
foo bar baz
Difference betweeen use of "$#" (array to array) and "$*" (array to string)
set -- foo bar 'foo bar' 'foo bar baz'
If I take 3 first elements:
someArray=("${#: 1: $# -1 }")
declare -p someArray
declare -a someArray=([0]="foo" [1]="bar" [2]="foo bar")
But
someArray=("${*: 1: $# -1 }")
declare -p someArray
declare -a someArray=([0]="foo bar foo bar")
There are about a thousand ways of doing this. As you would like to make use of integer arithmetic, you can do the following in bash
A short semi-cryptic version would be:
IFS=+
echo $(( ( ${*} - ${#:-1} ) / ${#:-1} ))
Here we make use of the difference between "${*}" and "${#}" to perform the sum by setting IFS=+ (See What is the difference between "$#" and "$*" in Bash?)
A long classic approach would be:
for i in "$#"; do ((s+=i)); done
echo $(( (s-${#:-1})/${#:-1} ))
It's easier to sum all terms and subtract the last term afterwards

What is the difference between "for i" and "for i in 1 2 3 4" in shell scripting?

I had to print all the arguments parsed in a shell script on a different line. I wrote a script as
for i in 1 2 3 4 5
do
echo $i
done
but this prints
1
2
3
4
5
even if i parse the arguments as "10 20 30 40 50"
and one code on the internet
for i
do
echo $i
done
this code prints the arguments correctly.
Can someone explain me why that code works but mine doesn't?
Also how can I use the value of one variable ($i) as the variable name to print something else. like
i=1
$($i)
should print the value of $1.
for i is equivalent to for i in "$#"
From Bash help for:
for: for NAME [in WORDS ... ] ; do COMMANDS; done
Execute commands for each member in a list.
The 'for' loop executes a sequence of commands for each member in a
list of items. If 'in WORDS ...;' is not present, then 'in "$#"' is
assumed. For each element in WORDS, NAME is set to that element, and
the COMMANDS are executed.
If in WORDS ...; is not present, then in "$#" is assumed
If you want to get the variable from a variable, use indirect expansion:
set -- arg1 arg2 arg3 foo
for i in 3 4 1 2
do
echo "${!i}"
done
# Output: arg3 foo arg2 arg1

convert inputs arguments to string with spaces [duplicate]

In shell scripts, what is the difference between $# and $*?
Which one is the preferred way to get the script arguments?
Are there differences between the different shell interpreters about this?
From here:
$# behaves like $* except that when quoted the arguments are broken up properly if there are spaces in them.
Take this script for example (taken from the linked answer):
for var in "$#"
do
echo "$var"
done
Gives this:
$ sh test.sh 1 2 '3 4'
1
2
3 4
Now change "$#" to $*:
for var in $*
do
echo "$var"
done
And you get this:
$ sh test.sh 1 2 '3 4'
1
2
3
4
(Answer found by using Google)
A key difference from my POV is that "$#" preserves the original number
of arguments. It's the only form that does. For that reason it is
very handy for passing args around with the script.
For example, if file my_script contains:
#!/bin/bash
main()
{
echo 'MAIN sees ' $# ' args'
}
main $*
main $#
main "$*"
main "$#"
### end ###
and I run it like this:
my_script 'a b c' d e
I will get this output:
MAIN sees 5 args
MAIN sees 5 args
MAIN sees 1 args
MAIN sees 3 args
With $# each parameter is a quoted string. Otherwise it behaves the same.
See: http://tldp.org/LDP/abs/html/internalvariables.html#APPREF

Passing a command as a variable to a function in Unix

Can you pass a command as a variable to another function? If yes, what is the syntax?
My code looks something like.
function1(){
for a in $1
do
echo $a
done
}
function2(){
function1 "ls -lrt folder/Name | grep 'foo' | grep 'bar'"
}
But this doesn't work. I even tried passing it as:
function1 `ls -lrt folder/Name | grep 'foo' | grep 'bar'`
But this passes only the first value of the command (and I understand why this happens).
Does anyone know the syntax to pass a command to function as a variable?
As indicated in comments, you are using $1 but this will just contain the first parameter. Instead, you need to use $#.
From Bash Manual → 3.4.2 Special Parameters:
$#
($#) 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" …. If the
double-quoted expansion occurs within a word, the expansion of the
first parameter is joined with the beginning part of the original
word, and the expansion of the last parameter is joined with the last
part of the original word. When there are no positional parameters,
"$#" and $# expand to nothing (i.e., they are removed).
Then you ask
What if the function1 takes multiple parameters? And the command is
the third parameter being passed, then using $# takes in some
unnecessary values. How do I take values from say $3 onwards?
For this, you want to use shift:
$ cat myscript.sh
#!/bin/bash
shift 2
echo "$#"
$ ./myscript.sh a b c d
c d
shift
shift [n]
Shift the positional parameters to the left by n. The positional
parameters from n+1 … $# are renamed to $1 … $#-n. Parameters
represented by the numbers $# to $#-n+1 are unset. n must be a
non-negative number less than or equal to $#. If n is zero or greater
than $#, the positional parameters are not changed. If n is not
supplied, it is assumed to be 1. The return status is zero unless n is
greater than $# or less than zero, non-zero otherwise.

What is the difference between $# and $* in shell scripts?

In shell scripts, what is the difference between $# and $*?
Which one is the preferred way to get the script arguments?
Are there differences between the different shell interpreters about this?
From here:
$# behaves like $* except that when quoted the arguments are broken up properly if there are spaces in them.
Take this script for example (taken from the linked answer):
for var in "$#"
do
echo "$var"
done
Gives this:
$ sh test.sh 1 2 '3 4'
1
2
3 4
Now change "$#" to $*:
for var in $*
do
echo "$var"
done
And you get this:
$ sh test.sh 1 2 '3 4'
1
2
3
4
(Answer found by using Google)
A key difference from my POV is that "$#" preserves the original number
of arguments. It's the only form that does. For that reason it is
very handy for passing args around with the script.
For example, if file my_script contains:
#!/bin/bash
main()
{
echo 'MAIN sees ' $# ' args'
}
main $*
main $#
main "$*"
main "$#"
### end ###
and I run it like this:
my_script 'a b c' d e
I will get this output:
MAIN sees 5 args
MAIN sees 5 args
MAIN sees 1 args
MAIN sees 3 args
With $# each parameter is a quoted string. Otherwise it behaves the same.
See: http://tldp.org/LDP/abs/html/internalvariables.html#APPREF

Resources