What is the bash equivalent to batchs' %* - bash

If I have a batch file and want to just use all given script arguments I can use %*.
Example a.bat
echo %*
Calling a.bat 1 2 3 4 gives:
1 2 3 4
how can I do the same in a bash script?

"$*" will return a single string with all the arguments separated by space.
"$#" will return N strings, one for each argument.
Example a.sh:
echo "$#"
Calling a.sh 1 2 3 4 gives:
1 2 3 4
Another example of a.sh:
printf "%s\n" "$#"
Calling a.sh 1 '2 2' '3 3 3' '4 4 4 4' gives:
1
2 2
3 3 3
4 4 4 4
As opposed to a.sh being:
printf "%s\n" "$*"
which will print:
1 2 2 3 3 3 4 4 4 4

Related

List of nums (column) in variable Bash

I want to create code that creates a variable containing the number of positional arguments as a consecutive list.
For example, if the number of positional arguments ($#) is 5 then:
var='
1
2
3
4
5'
Use seq
echo "$#"
5
var=$(seq 1 $#)
echo "$var"
1
2
3
4
5
Try it online!

bash shell scripting transpose rows and columns

I need help transposing a file that just simply has some numbers in them with rows and columns. I can't use awk shell or perl so it makes it kind of hard. I've been working on it for a couple of hours and can't get it working correctly. I tried a couple of other things but this is what I have right now. It runs, but it doesn't print out anything, so that leads me to conclude that something is wrong within my code. Also if you dont know by transpose if a file had :
1 2 3
4 5 6
... it would then print out
1 4
2 5
3 6
Here is my code:
if [ $# -gt 2 ]
then
echo"System error">&2
exit 1
elif [[ $# -eq 2 && -e "$2" && -r "$2" ]]
then
while read -a line; do
for ((i=0; i < "${#line[#]}"; i++)); do
a[$i]="${a[$i]} ${line[$i]}"
done
done < $2
for ((i=0; i < ${#a[#]}; i++)); do
echo ${a[i]}
done
fi
If possible use awk:
Source (file.txt):
1 2 3
4 5 6
Result:
1 4
2 5
3 6
Oneline awk sctript:
awk '{ for (i=1; i<=NF; i++) a[i]= (a[i]? a[i] FS $i: $i) } END{ for (i in a) print a[i] }' file.txt
It works same with
1 2 3 1 4 7
4 5 6 -> 2 5
7 3 6
and with
1 2 3 4 1 5
5 6 7 -> 2 6
3 7
4
Instead of writing a Bash function, we could use rs, written specifically for reshaping matrices. This command does exactly what you ask for:
rs -T

Passing arguments to another script, after having used the "shift" builtin

Consider a simple script program.sh:
$ cat program.sh
echo program: I have "$#" arguments, they are "$#"
$ ./program.sh 1 2 3
program: I have 3 arguments, they are 1 2 3
$ ./program.sh '1 1' 2 3
program: I have 3 arguments. they are 1 1 2 3
Now I want a wrapper script wrapper.sh that invokes program.sh in the same way it was invoked:
$ cat wrapper.sh
echo wrapper: I have "$#" arguments, they are "$#"
./program.sh "$#"
$ ./wrapper.sh 1 2 3
wrapper: I have 3 arguments, they are 1 2 3
program: I have 3 arguments, they are 1 2 3
$ ./wrapper.sh '1 1' 2 3
wrapper: I have 3 arguments. they are 1 1 2 3
program: I have 3 arguments. they are 1 1 2 3
This works perfectly, but I want to use the shift builtin within wrapper.sh, which creates a problem because then I cannot use "$#" anymore in the invocation to program.sh:
$ cat wrapper.sh
echo wrapper: I have "$#" arguments, they are "$#"
shift
./program.sh "$#"
$ ./wrapper.sh 1 2 3
wrapper: I have 3 arguments, they are 1 2 3
program: I have 2 arguments, they are 2 3
$ ./wrapper.sh '1 1' 2 3
wrapper: I have 3 arguments. they are 1 1 2 3
program: I have 2 arguments. they are 2 3
I have tried initially setting the value of $# to a temporary variable, but nothing I tried seems to work for wrapper.sh to invoke program.sh exactly the way it was originally invoked. What is the proper way to handle this?
It is easy to save $#. Just save it as an array:
$ cat wrapper.sh
echo wrapper: I have "$#" arguments, they are "$#"
save=("$#")
shift
./program.sh "${save[#]}"
This produces the output:
$ wrapper.sh '1 1' 2 3
wrapper: I have 3 arguments, they are 1 1 2 3
program: I have 3 arguments, they are 1 1 2 3
The key here is that save is a bash array. Trying to store $# as a shell string does not work. Saving it as an array does work.

How to remove nth element from command arguments in bash

How to I remove the nth element from an argument list in bash?
Shift only appears to remove the first n, but I want to keep some of the first. I want something like:
#!/bin/sh
set -x
echo $#
shift (from position 2)
echo $#
So when I call it - it removes "house" from the list:
my.sh 1 house 3
1 house 3
1 3
Use the set builtin and shell parameter expansion:
set -- "${#:1:1}" "${#:3}"
would remove the second positonal argument.
You could make it generic by using a variable:
n=2 # This variable denotes the nth argument to be removed
set -- "${#:1:n-1}" "${#:n+1}"
a=$1
shift; shift
echo $a $#
If someone knows how to do this in a better way I am all ears!
If you want to use bash you can use a bash array
#!/bin/bash
arg=($0 $#)
or if you don't need argument $0
arg=($#)
# argument to remove
rm_arg=2
arg=(${arg[#]:0:$rm_arg} ${arg[#]:$(($rm_arg + 1))})
echo ${arg[#]}
Now instead of referencing $1 you might use ${arg[1]} .
Remember that bash arguments has an argument $0 and bash arrays have an element [0]. So, if you don't assign bash argument $0 to the first element of a bash array [0] , Then you will find bash argument $1 in your bash array [0] .
arg=($#)
for VAR in $#; do
case $VAR in
A)
echo removing $VAR
arg=($(echo $#| sed "s/$VAR//"))
;;
*)
echo ${arg[#]}
;;
esac
done
Results:
./test.sh 1 2 3 A 4 5
1 2 3 A 4 5
1 2 3 A 4 5
1 2 3 A 4 5
removing A
1 2 3 4 5
1 2 3 4 5

Delete positional parameters in Bash?

You can skip positional parameters with shift but can you delete positional parameters by passing the position?
x(){ CODE; echo "$#"; }; x 1 2 3 4 5 6 7 8
> 1 2 4 5 6 7 8
I would like to add CODE to x() to delete positional parameter 3. I don't want to do echo "${#:1:2} ${#:4:8}". After running CODE, $# should only contain "1 2 4 5 6 7 8".
The best way, if you want to be able to pass on the parameters to another process, or handle space separated parameters, is to re-set the parameters:
$ x(){ echo "Parameter count before: $#"; set -- "${#:1:2}" "${#:4:8}"; echo "$#"; echo "Parameter count after: $#"; }
$ x 1 2 3 4 5 6 7 8
Parameter count before: 8
1 2 4 5 6 7 8
Parameter count after: 7
To test that it works with non-trivial parameters:
$ x $'a\n1' $'b\b2' 'c 3' 'd 4' 'e 5' 'f 6' 'g 7' $'h\t8'
Parameter count before: 8
a
1 2 d 4 e 5 f 6 g 7 h 8
Parameter count after: 7
(Yes, $'\b' is a backspace)
x(){
#CODE
params=( $* )
unset params[2]
set -- "${params[#]}"
echo "$#"
}
Input:
x 1 2 3 4 5 6 7 8
Output:
1 2 4 5 6 7 8
From tldp
# The "unset" command deletes elements of an array, or entire array.
unset colors[1] # Remove 2nd element of array.
# Same effect as colors[1]=
echo ${colors[#]} # List array again, missing 2nd element.
unset colors # Delete entire array.
# unset colors[*] and
#+ unset colors[#] also work.
echo; echo -n "Colors gone."
echo ${colors[#]} # List array again, now empty.
You can call set and reset the positional paramaters at any time
for example
function q {
echo ${#}
set $2 $3 $4
echo ${#}
set $4
echo ${#}
}
q 1 2 3 4
then slice out what you dont want from the array, the below code does that... not sure if its the best way to do it though, was on stack looking for a better way ; )
#!/bin/bash
q=( one two three four five )
echo -e "
(remove) { [:range:] } <- [:list:]
| [:range:] => return list with range removed range is in the form of [:digit:]-[:digit:]
"
function remove {
if [[ $1 =~ ([[:digit:]])(-([[:digit:]]))? ]]; then
from=${BASH_REMATCH[1]}
to=${BASH_REMATCH[3]}
else
echo bad range
fi;shift
array=( ${#} )
local start=${array[#]::${from}}
local rest
[ -n "$to" ] && rest=${array[#]:((${to}+1))} || rest=${array[#]:((${from}+1))}
echo ${start[#]} ${rest[#]}
}
q=( `remove 1 ${q[*]}` )
echo ${q[#]}
while loop over "$#" with shift + set: move each parameter from first to last position, except "test"
# remove option "test" from positional parameters
i=1
while [ $i -le $# ]
do
var="$1"
case "$var" in
test)
echo "param \"$var\" deleted"
i=$(($i-1))
;;
*)
set -- "$#" "$var"
;;
esac
shift
i=$(($i+1))
done

Resources