Let say I have this line in a shell script in unix:
read -n 1
It will prompt the user to get value but is there a way to call the script so it takes the input as argument instead?
Like this for example:
myscript.sh "M"
I want to call the script from a build engine so it cannot answer with keyboard input.
To use argument values in shell script you can pass the argument with the script and then refer them using $1, $2, $3 and so on.
You can use Here Strings in bash:
myscript.sh <<< "M"
Or use pipeline:
echo "M" | myscript.sh
Here string documentation
Use this with some frequency:
hello() { read -n1 CHAR; echo $CHAR; }
echo world | hello
How about
myscript.sh $(read -n 1)
?
Related
I am passing a variable to a function that has been loaded from a config file. This variable is in turn passed on to a grep. I have tried several ways to expand the search variable ($1) but none seem to work, however the file to search works fine ($2).
Can someone advise what is the correct way to present the variable to the grep function. I have tried
"$1", "${1}", $1, ${1}, "${!1}
UPDATE Based on answers I have updated the script.sh to refelect the actual script complexity as it still does not work.
thanks
Art
Working code with no variable for RouteTableId
MyVar=$(grep -m 1 "RouteTableId" $2)
Not Working code with variable for RouteTableId
config.file
myTerm="RouteTableId"
myFile="my.file"
script.sh
. config.file
myFunction(){
mySubFunction(){
myVar=$(grep -m 1 "$1" $2)
echo $myVar
}
mySubFunction ${!1} ${!2}
}
myFunction "myTerm" "myFile"
UPDATE
I have done some more tests and it turns out that when passing variables between functions, in some circumstances the numbering order changes if one of the sequence is null. for example if i call myFunction with the following, the 2nd variable being null
myFunction "myTerm" "blah" "myFile"
then myFunction will see the following
echo "${!1}, ${!2}, ${!3}"
RouteTableId,,my.file
and then passing this to mySubFunction
mySubFunction ${!1} ${!3}
gives from within mySubFunction
echo "${!1}, ${!2}, ${!3}"
RouteTableId,my.file,
so it seems the null is being removed in the order and the subsequent variables are being brought forward in the number order.
If someone can validate and explain why I would appreciate it.
thx
Art
You are not passing the values of the variables but the variable names themselves as values.
i.e.
myFunction "myTerm" "myFile"
should be
myFunction "$myTerm" "$myFile"
If this isn't what you expect, you should edit your question to better define what it is you do expect:
$ cat my.file
foo
Here it is: RouteTableId
bar
$
$ cat config.file
myTerm="RouteTableId"
myFile="my.file"
$
$ cat script.sh
. config.file
myFunction() {
mySubFunction() {
myVar=$(grep -m 1 "$1" "$2")
echo "$myVar"
}
mySubFunction "${!1}" "${!2}"
}
myFunction "myTerm" "myFile"
$
$ ./script.sh
Here it is: RouteTableId
From your recent update, I think you are confused about what $1, etc. means. In a shell script but outside of any function $1 is the first arg passed to the shell script. In a function within a shell script $1 is the first arg passed to that function, NOT the first arg passed to the shell script. So if you do:
func() {
echo "$1,$2,$3"
}
func "$1" "$3"
then you will get the values of the first arg passed to the script (since that is also the 1st arg passed to the function), then a comma, then the 3rd arg passed to the script (since that is the 2nd arg passed to the function) and then another comma and that is all (because there is no 3rd arg passed to the function).
Hope that makes sense.
I have a bash script I am working on where I need to pass two arguments into a function. When I run the script everything works fine, except when it parses through the file I pass to it, the result I always get is Association (this is written in the text file). Can you advise what I would need to do so that it parses the correct info, which should be what I would type in as uid? I wrote in the input 123456789 because that's in the text file, but again I am getting Association as the result instead.
echo "Please enter the UID: ";
read uid
echo "Please enter server file: ";
read server
uidAssoc(){
arg1=$1
arg2=$2
for arg1 in $(cat ~/jlog/"$2"); do awk 'match($i, $2){ print substr($i, RSTART, RLENGTH)} ' ~/jlog/"$2";done;}
uidAssoc "$uid" "$server"
exit
The closing brace of the function requires whitespace in front of it (reference). Formatting your code more readably will help.
uidAssoc(){
arg1=$1
arg2=$2
for arg1 in $(cat ~/jlog/"$2"); do
awk 'match($i, $2){ print substr($i, RSTART, RLENGTH)} ' ~/jlog/"$2"
done
}
Some questions for you:
Why do you assign arg1 and arg2 but never use them?
What is $i in your awk script? (since i is unset, that will eventually evaluate to the whole line)
Are you aware that the $2 inside single quotes is different from the $2 outside of single quotes?
Im trying to create a bourne shell script that will take 0 or more arugments and print out the last arugment, I am use to writing Java and im so confused by this, slowly starting to learn C.
An alternative to #Michael's solution:
#!/usr/bin/env bash
echo "${#: -1}"
$# is the array with all the parameters.
: is used to split strings normally (you can try this with echo "${USER: -1}" to verify that it prints the last character of your user name), but can also be used for arrays to get the last element.
The curly brackets are needed for the array indexing to work
The quotes are simply good practice, to make the code more flexible in case you want to mix in other variables, or the value needs to be used in a statement which needs an empty string rather than nothing in case of no parameters (for example if [ "${#: -1}" = "--help" ])
lastArg=`echo $# | awk '{print $NF}'`
Here is a short Bash script that will do it:
#!/usr/bin/env bash
echo "${!#}"
This is not a Bourne shell script, though. Args are not read from the keyboard with the read command. Instead they are supplied on the command line when running your script. For example, if you put this text in script.sh and run ./script.sh a b c d e it will print:
e
In bash:
last_arg=`echo $* | rev | cut -d " " -f1 | rev`;
echo $last_arg
Your question mentions C. In C its easier:
int main (int argc, char *argv[]) {
char *last_arg = argv[argc - 1];
[...]
}
This should work:
eval lastarg='$'$#
echo last arg is $lastarg
This works with /bin/sh being bash or dash.
I am unable to test it with a "real" /bin/sh, whatever that would be.
I have a Perl script that gives me a defined list of random numbers that correspond to the lines of a file. Next I want to extract those lines from the file using sed.
#!/bin/bash
count=$(cat last_queries.txt | wc -l)
var=$(perl test.pl test2 $count)
The variable var returns an output like: cat last_queries.txt | sed -n '12p;500p;700p'. The problem is that I can't run this last command. I tried with $var, but the output is not correct (if I run manually the command it works fine, so no problem there). What is the correct way to do this?
P.S: Sure I could do all the work in Perl, but I'm trying to learn this way, because it could help me in other situations.
You just need to do:
#!/bin/bash
count=$(cat last_queries.txt | wc -l)
$(perl test.pl test2 $count)
However, if you want to call your Perl command later, and that's why you want to assign it to a variable, then:
#!/bin/bash
count=$(cat last_queries.txt | wc -l)
var="perl test.pl test2 $count" # You need double quotes to get your $count value substituted.
...stuff...
eval $var
As per Bash's help:
~$ help eval
eval: eval [arg ...]
Execute arguments as a shell command.
Combine ARGs into a single string, use the result as input to the shell,
and execute the resulting commands.
Exit Status:
Returns exit status of command or success if command is null.
You're are probably looking for eval $var.
line=$((${RANDOM} % $(wc -l < /etc/passwd)))
sed -n "${line}p" /etc/passwd
just with your file instead.
In this example I used the file /etc/password, using the special variable ${RANDOM} (about which I learned here), and the sed expression you had, only difference is that I am using double quotes instead of single to allow the variable expansion.
There're 2 basic ways of executing a string command in a shell script whether it's given as parameter or not here's.
COMMAND="ls -lah"
$(echo $COMMAND)
or
COMMAND="ls -lah"
bash -c $COMMAND
In the case where you have multiple variables containing the arguments for a command you're running, and not just a single string, you should not use eval directly, as it will fail in the following case:
function echo_arguments() {
echo "Argument 1: $1"
echo "Argument 2: $2"
echo "Argument 3: $3"
echo "Argument 4: $4"
}
# Note we are passing 3 arguments to `echo_arguments`, not 4
eval echo_arguments arg1 arg2 "Some arg"
Result:
Argument 1: arg1
Argument 2: arg2
Argument 3: Some
Argument 4: arg
Note that even though "Some arg" was passed as a single argument, eval read it as two.
Instead, you can just use the string as the command itself:
# The regular bash eval works by jamming all its arguments into a string then
# evaluating the string. This function treats its arguments as individual
# arguments to be passed to the command being run.
function eval_command() {
"$#";
}
Note the difference between the output of eval and the new eval_command function:
eval_command echo_arguments arg1 arg2 "Some arg"
Result:
Argument 1: arg1
Argument 2: arg2
Argument 3: Some arg
Argument 4:
Better ways to do it
Using a function:
# define it
myls() {
ls -l "/tmp/test/my dir"
}
# run it
myls
Using an array:
# define the array
mycmd=(ls -l "/tmp/test/my dir")
# run the command
"${mycmd[#]}"
cmd="ls -atr ${HOME} | tail -1" <br/>
echo "$cmd" <br/>
VAR_FIRST_FILE=$( eval "${cmd}" ) <br/>
or
cmd=("ls -atr ${HOME} | tail -1") <br/>
echo "$cmd" <br/>
VAR_FIRST_FILE=$( eval "${cmd[#]}" )
I have a bash script
fooA
#!/bin/bash
script_name=$1;
script_params=$( echo $# | awk '{ $1=""; print $0 }' );
bash /path/to/scripts/$script_name $script_params > /dev/stdout;
and another script fooB in the .../scripts/ directory.
#!/bin/bash
echo 1. $1
echo 2. $2
My plan is simple:
fooA fooB "some sentence 1" "some sentence 2"
should produce:
some sentence 1
some sentence 2
Using my current script, I would get
some
sentence
Because the double quotes are not preserved when calling fooB from fooA.
Keeping in mind that there many other scripts in the .../scripts directory, how would I change the script_params=$(...) line in fooA file to preserve variables when calling other scripts.
#jm666's answer will work fine if there are no additional constraints. For completeness, though, I'll give a version that doesn't mess with the first script's argument list:
#/bin/bash
script_name="$1"
script_params=( "${#:2}" )
bash /path/to/scripts/"$script_name" "${script_params[#]}" > /dev/stdout
Or you can skip the variables entirely:
#/bin/bash
bash /path/to/scripts/"$1" "${#:2}" > /dev/stdout
#!/bin/bash
name="$1"
shift
"/path/to/script/$name" "$#"