Why 'test=6 echo $test' command doesnot work in bash? - bash

I came across this neat command to check the time of any timezone in bash
TZ=US/Hawaii date
Which does same as
export TZ=US/Hawaii
date
How does the first command work, while the following command doesn't work?
test=6 echo $test

Variables are expanded before executing the commands in a line. So in the last example, $test is expanded before the assignment is done.
You can get the effect you want with:
test=6 bash -c 'echo $test'
This executes a new shell process. Since the argument is quoted, variables aren't expanded by the original shell, the subshell expands it in the environment where $test is set.

In the first, the call to date uses the value of TZ that is put in its environment. In the second, the expansion of $test is performed by the shell before echo is actually run. The value of test in echo's environment is irrelevant. A near-equivalent that works would be
(test=6; echo $test)

Related

What is ${command_} in a shell script

I have googled and found nothing. I am reading a shell script file and there there is this line
echo "docker run command"
echo ${command_}
What does this mean? Please notice that
there is an underscore after "command"
command_ seems not to be defined elsewhere
What is ${command_} in a shell script
${command_} means to expand the variable named command_ to it's value.
What does this mean?
echo "docker run command" - means to execute the command echo (possibly a builtin) with one argument docker run command.
echo ${command_} - means to execute the command echo (possibly a builtin) with the result of expansion of the variable command_ will undergo word splitting expansion and then the result will be passed as arguments to the echo command.
there is an underscore after "command"
It doesn't matter - underscore is nothing special.
command_ seems not to be defined elsewhere
That means that ${command_} expansion will expand to an empty string, and the second echo will run with no arguments.
echo command is used to print the arguments passed. But if argument has $ to it, it means it evaluates its value and prints the same.
Here, you shell script would be having a variable named "command_". It'll just find its value, if defined, and print it. If its not defined, nothing will be printed.

Why can't a string variable be evaluated as a command when using ${!variable}?

This is somehow related to Use substituted string as a command in shell script I asked last year. That accepted answer worked nicely.
#!/usr/bin/env bash
for user in ytu
do
cd /home/${user}/H2-Data/crons
for path in "$user"_*_monthly_report.py
do
if [ -e $path ]
then
. ../../.profile
userpython=${user^^}_PYTHON
echo ${!userpython} $path
else
break
fi
done
done
This echos what I expected:
/home/ytu/anaconda3/bin/python ytu_clinic217_monthly_report.py
/home/ytu/anaconda3/bin/python ytu_clinic226_monthly_report.py
However, by simply changing ${user^^}_PYTHON to $YTU_PYTHON, which should be exactly the same in this case, the bash script now echos:
ytu_clinic217_monthly_report.py
ytu_clinic226_monthly_report.py
I even tried userpython=/home/ytu/anaconda3/bin/python but that ends up the same. That said, if I echo $userpython, I can still get /home/ytu/anaconda3/bin/python in the latter cases.
I wonder why can't userpython be evaluated anymore by simply assigning the variable explicitly, and how can I make it right?

what is the meaning of FOOBAR=foobar followed by a shell command?

I see in shell scripts a variable assignment followed (without a semicolon) by a command. What is the meaning of that? It does not seem to affect this command, and it does not seem to affect the next command the way normal assignment would:
>echo $FOOBAR
>FOOBAR=1 echo $FOOBAR
>echo $FOOBAR
>
So, what does it do?
It sets that environment variable to that value only for that process.
Here, step by step, is what happens:
Original command: FOOBAR=1 echo $FOOBAR
Shell performs substitution: command is now FOOBAR=1 echo
Shell fork(2)s a new process
Environment variable is created in the new process: command is now echo (with $FOOBAR equal to 1)
New process is exec(3)ed: \n is output
New process exits and is reaped by the shell
At no point does the parent process see the assigned value of $FOOBAR.
On first run of echo $FOOBAR you will get empty result on your screen as the FOOBAR variable is not set yet.
Then when you set it to 1,and run it on the second time it will display 1.
Note: This value will be lost when you close your terminal where you wrote these. $ notation in shell and shell scripting in Unix like environments simply denotes a variable.
What happens in your case in second command i.e FOOBAR=1 echo $FOOBAR is that the line is not syntactically incorrect but it breaches the contract of equalto(=) which actually does not accept a space thus no error is thrown and FOOBAR=1 is just treated as a parameter and it fails while the command for echo executes successfully.
I would suggest try this :
FOOBAR=1
echo $FOOBAR
in different lines or
FOOBAR=1 ; echo $FOOBAR in one line.

Bash command line arguments, replacing defaults for variables

I have a script which has several input files, generally these are defaults stored in a standard place and called by the script.
However, sometimes it is necessary to run it with changed inputs.
In the script I currently have, say, three variables, $A $B, and $C. Now I want to run it with a non default $B, and tomorrow I may want to run it with a non default $A and $B.
I have had a look around at how to parse command line arguments:
How do I parse command line arguments in Bash?
How do I deal with having some set by command line arguments some of the time?
I don't have enough reputation points to answer my own question. However, I have a solution:
Override a variable in a Bash script from the command line
#!/bin/bash
a=input1
b=input2
c=input3
while getopts "a:b:c:" flag
do
case $flag in
a) a=$OPTARG;;
b) b=$OPTARG;;
c) c=$OPTARG;;
esac
done
You can do it the following way. See Shell Parameter Expansion on the Bash man page.
#! /bin/bash
value=${1:-the default value}
echo value=$value
On the command line:
$ ./myscript.sh
value=the default value
$ ./myscript.sh foobar
value=foobar
Instead of using command line arguments to overwrite default values, you can also set the variables outside of the script. For example, the following script can be invoked with foo=54 /tmp/foobar or bar=/var/tmp /tmp/foobar:
#! /bin/bash
: ${foo:=42}
: ${bar:=/tmp}
echo "foo=$foo bar=$bar"

Problem in running a script

i have unix shell script which is need to be run like below
test_sh XYZ=KLMN
the content of the script is
#!/bin/ksh
echo $XYZ
for using the value of XYZ i have do set -k before i run the script.
is there a way where i can do this without doint set -k before running the script. or is there something that i can do in the script where i can use value of the parameter given while running the script in the below way
test_sh XYZ=KLMN
i am using ksh.
Any help is appreciated.
How about running this?
XYZ=KLMN ./test_sh //running from directory where test_sh is
If your script needs no other arguments, a quick and dirty way do to it is to put
eval "$#"
at the start of your script. This will evaluate the command line arguments as shell commands. If those commands are to assign a shell/environment variable, then that's what it will do.
It's quick-and-dirty since anything could be put on the command line, causing problems from a syntax error to a bad security hole (if the script is trusted).
I'm not sure if "$#" means the same in ksh as it does in bash - using just $* (without quotes) would work too, but is even dirtier.
It looks like you are trying to use the environment variable "INSTANCE" in your script.
For that, the environment variable must be set in advance of executing your script. Using the "set" command sets exportable environment variables. Incidentally, my version of ksh dates from 1993 and the "-k" option was obsolete back then.
To set an environment variable so that it is exported into spawned shells, simply use the "export" command like so:
export INSTANCE='whatever you want to put here'
If you want to use a positional parameter for your script -- that is have the "KLMN" value accessed within your script, and assuming it is the first parameter, then you do the following in your script:
#!/bin/ksh
echo $1
You can also assign the positional parameter to a local variable for later use in your script like so:
#!/bin/ksh
param_one=$1
echo $param_one
You can call this with:
test_sh KLMN
Note that the spacing in the assignment is important -- do not use spaces.
I am tring this option
#!/bin/ksh
echo $1
awk '{FS="=";print $2}' $1
and on the command line
test_sh INSTANCE=LSN_MUM
but awk is failing.is there any problem over here?
Probably #!/bin/ksh -k will work (untested).

Resources