Is it possible to create a script that will prompt a user to enter a number that will then programmatically be used for the number of arguments in a function/method? For example:
echo "Enter Number of arguments: "
read numOfArguments
Once a number is entered, this will stand for the number of parameters in a function. So if I enter 5, there should be 5 expected parameters within that method once called:
sampleMethod(){
...Takes 5 Parameters and actual code is here
}
sampleMethod ActualArgumentsfromPrompt
If this is possible can someone provide an example of how this is done? I am doing this because I would like to create a script that will parse through a log file but I need to pull specific items from the log that are set up similar to this: (0010,0020). The information I need will not always be a fixed number of items so that's why I would like to generate a prompt for a number of arguments.
Bash functions don't "expect" any number of arguments -- as you can see from the syntax, there's no list of parameter variables after the function name. They process arguments the same way the main shell does, by accessing them as $1, $2, etc. If you need to know how many arguments were passed, you can use $#.
To loop through all arguments, the common idiom is to process $1, then use shift to shift the argument list down.
sampleMethod() {
if [ $# -ne $numOfArguments ]
then echo Wrong number of arguments -$numOfArguments expected, $# provided >&2
return
fi
while [ $# -gt 0 ]; do
arg=$1
echo "$arg"
shift
done
}
Related
This question already has answers here:
Parsing command line arguments in a shell script function
(1 answer)
How can I compare numbers in Bash?
(10 answers)
Closed last year.
This might be a naive question, but I am new to bash scripting. I am trying to open a file and count the number of lines in that file and if it is greater than 4, then output something. I have figured out how to pass and save the line count to a variable, but I cannot access the file in the bash when I do not pass it the exact name. Therefore, I have this program called new_test written as so:
test_function()
{
file_name='test_text.txt'
n=$(wc -l < $file_name)
if [ 'n > 2' ]
then
echo "Too many lines"
fi
}
test_function
This program works, but when I try and make it more generic to accept any file by changing line 3 from:
file_name='test_text.txt'
to
file_name=$1
And then call
./new_test test_text.txt
it outputs:
./test_file[4]: : cannot open
From my understanding, the $1 is the second argument passed, and in the case of ./new_test test_text.txt, this would be the test_text.txt file. Do I need to obtain the address of the second argument or is the notation different in order to do this? Thank you in advance.
The $1 inside of the function is the function argument, not the script argument. You need to take that top level argument and pass it back into the function itself.
test_function()
{
file_name="$1"
n=$(wc -l < $file_name)
if [ 'n > 2' ]
then
echo "Too many lines"
fi
}
test_function "$1"
Make sure you don't forget the quotes either, or you'll run into problems with files that have spaces in their path.
Can anyone help me with this code? bash doesn't recognize the $2 only the first $1 show an error: read: '2': it is not a valid identificator.
#!/bin/bash
read $#
a=$#
You cannot read into $#, or into the variable called 2 (which $# expands to).
Instead, to reassign $2, you need to use set to completely rewrite the full set of positional parameters:
set -- one two
...will set $2 to two, and $# to 2 (since two items were provided).
By contrast, if you simply wish to use the value for $2 passed on your script's command line, you don't need to (and shouldn't) use read at all.
By contrast, if you want to access the last command-line argument, you can use indirect expansion for that:
set -- one two last
last_arg=$# # sets last_arg=3
result=${!last_arg} # sets result=last
...or, if you want to overwrite the last command-line argument with a value read from stdin:
read new_last
set -- "${#:1:$(( $# - 1 ))}" "$new_last"
I have a script that receive parameters from user input, but can have also have parameters coming from an environment variable.
e.g. :
export ADZ_DEPLOY_OPT="--from-git --rootDir XXXXXXX"
and in my script, I attempt to do something like :
$*="${ADZ_DEPLOY_OPT} $*"
while [[ $# -gt 1 ]]
do
key="$1"
case $key in
--rootDir)
ADZ_ROOT_DIR="$2"
shift # past argument
;;
--tagVersion)
ADZ_TAG_VERSION="$2"
shift # past argument
;;
--from-git)
ADZ_DEPLOY_FROM_GIT=1
;;
*)
# unknown option
;;
esac
shift # past argument or value
done
Except it doesn't work as it generates an error when I try to update $* to expand it with additional values - and I couldn't succeed to find a way to achieve this behavior.
The idea also is that the env variable will act as 'default' but may be overriden by what the user explicitly provide on the command line. That is with my example, if the user specify another rootDir, I want the user rootDir to be taken into account.
At last, I would like to keep long parameter names (I like being explicit) and therefore the use of getopts doesn't seem like an option.
Any help would be much appreciated !
Thanks in advance.
Replace
$*="${ADZ_DEPLOY_OPT} $*"
with:
set -- ${ADZ_DEPLOY_OPT} "$#"
Notes:
As bash is designed, one cannot assign directly to $*. Assignments are done with the set builtin.
You want to use "$#" not $*. The form $* is subjected to word splitting and the expansion of "$#" is not.
From your sample value for ADZ_DEPLOY_OPT, you do need word splitting for it. If you try to put complicated arguments in ADZ_DEPLOY_OPT, this won't work: you will need to use an array instead.
I need to print the argument number of which user types in. No matter what I do I always get just an empty line
echo "Give argument number"
read number
allV=$#
echo ${allV[$number]}
what is wrong with this few lines? Even if I start the script with a few arguments and I just manually write sth like"
echo ${allV[1]}
again all I get is an empty line.
Bash lets you use an indirect reference, which works also on numbered parameters:
echo "${!number}"
It also lets you slice the argument list:
echo "${#:$number:1}"
Or you could copy the arguments into an array:
argv=("$#")
echo "${argv[number]}"
In all cases, the quotes are almost certainly required, in case the argument includes whitespace and/or glob characters.
To handle $# as an array, just change it to ("$#") :
echo "Give argument number"
read number
allV=("$#")
echo ${allV[$number-1]}
My script is called by a program that generates argument randomly such as
input=12 output=14 destinationroute=10.0.0.0
and then calls my script with the generated arguments:
./getroute.sh input=12 output=14 destinationroute=10.0.0.0
Inside the script is like:
#!/bin/bash
input=$1
output=$2
destinationroute=$3
...
The program always calls arguments in random order (ex. input=12 output=14 or output=14 input=12), and I can't change the program.
Is there any way to recognize the correct parameters and put them in their proper place.
Don't rely on order if they aren't in order. Just iterate over the arguments, look at which patterns they match, and assign to a variable appropriately:
for arg; do # default for a for loop is to iterate over "$#"
case $arg in
'input='*) input=${arg#*=} ;;
'output='*) output=${arg#*=} ;;
'destinationroute='*) destinationroute=${arg#*=} ;;
esac
done
If, for some reason, you really wanted to update $1, $2, and $3, though, you can do that by putting the following code after the above loop:
set -- "$input" "$output" "$destinationroute"
you need to call your function differently; For exmple:
./getroute.sh -i 12 -o 14 -d 10.0.0.0
Then inside your script use getopt to read the variables.
Edit:
My scripting knowledge is not strong; therefore, there should be a better way to do it.
As you don't have access to the Program, you can add some lines inside your script to get the inputs; for example:
input=`echo $* | grep -E -o "input=[0-9]{2}" | awk -F"=" {'print$2'}`
You can do the same thing for other variables.