This question already has answers here:
Setting an argument with bash [duplicate]
(2 answers)
Closed 5 years ago.
I have to use a bash script (I'm not familiar with bash) for submitting a HPC job. The job-submission script template sets the command and options and then combines them in the end:
input="file_name"
name="simulation1"
application=my_app
options="in=$input.h5 out=$name.h5 param1=foo"
cmd="$application $options"
this all works okay, i.e. eval $cmd executes
my_app in=$input.h5 out=$name.h5 param1=foo
until I need the character '>' in the options. In particular, I want to add the option absrad="mass>1?H:0", but if I simply set
options="in=$input.h5 out=$name.h5 param1=foo absrad=mass>1?H:0"
then bash truncates that at the '>', so that eval $cmd executes
my_app in=$input.h5 out=$name.h5 param1=foo absrad=mass
instead. How to fix that such that eval $cmd executes
my_app in=$input.h5 out=$name.h5 param1=foo absrad="mass>1?H:0"
EDIT. Note that this is similar to, but not a duplicate of this post, where a single-quoted argument is the problem. Moreover, the answers there only consider solutions using an array for the options. I would like alternatives w/o array.
You could always use an array for options:
declare -a options=("in=$input.h5" "out=$name.h5" "param1=foo" "absrad=\"mass>1?H:0\"");
declare -a cmd=(my_app "${options[#]}");
Then when you want to expand cmd the following should give you the correct expansion:
"${cmd[#]}"
Additionally, this gets rid of the need to use eval, which I tend to avoid whenever possible.
Related
This question already has an answer here:
How can I create a bash environment variable that prefixes an environment variable before a command?
(1 answer)
Closed 1 year ago.
On Bash, I first define a variable CMD for a command line bash instruction, then I run it. An error occurs. Where does it go wrong?
$ CMD="VERBOSE=1 ./myscript"
$ $CMD
bash: VERBOSE=1: command not found
Don't store commands in variables. Variables aren't smart enough to hold commands. They will let you down time and time again like your roommate that never washes the dishes.
Use a function. They're the right tool for the job. You can use them like they were regular executables; they can take arguments; there are no quoting/backslash/whitespace issues.
$ cmd() {
> VERBOSE=1 ./myscript
> }
$ cmd
Functions are where it's at.
See also:
How can I create a bash environment variable that prefixes an environment variable before a command?
This question already has answers here:
How to execute a bash command stored as a string with quotes and asterisk [duplicate]
(5 answers)
Closed 2 years ago.
I want to compose a command in a shell script like this:
#!/bin/sh
APPLICATION="date"
PARAMETER="-d '2020-01-01 1:23'"
CMD="${APPLICATION} ${PARAMETER}"
${CMD}
The 'PARAMETER' is supposed to hold parameters that need to be quoted themself. Unfortunately it does not work like this. Escaping them via PARAMETER="-d \"2020-01-01 1:23\"" also does not work.
After you've build CMD up, it is just string. It contains what can be interpreted by you as a command, but the shell sees it as a bare string.
If you want the string to reinterpret it, you need to eval it:
eval "$CMD"
However, eval is often considered evil.
This question already has answers here:
How to store curly brackets in a Bash variable
(2 answers)
Closed 4 years ago.
I'm trying to use this variable
MediaExt="*.{mp4,mkv,avi}"
in this command
mv ${MediaSource}/${MediaExt} ${UploadDir}
but it doesn't seem to work.
Could someone help me, please? Thanks!
A command in bash is parsed in several passes. The pass that decides whether globbing (expanding *, or *.{mp4,mkv,avi}) should be performed, is occurring before the pass that expands the variables. Once the variables are expanded, there are candidate for globbing, but the decision that no globbing is required has already been made
It will work if you write the expression as:
mv ${MediaSource}/*.{mp4,mkv,avi} ${UploadDir}
You'll probably find some advise that you can use eval. Please don't!
This:
eval mv ${MediaSource}/${MediaExt} ${UploadDir}
will execute as you intended, but eval can be dangerous if you don't control the values of the variables. For example, if UploadDir could be set to:
UploadDir="somedirectory; rm -rf ~"
then eval will execute your request as two statements and remove all your files.
This question already has answers here:
Can I alias a subcommand? (shortening the output of `docker ps`)
(4 answers)
How to write an alias for "two" words [duplicate]
(2 answers)
Closed 5 years ago.
All the documentation I've looked at seems to indicate that in both aliases and shell functions, the name cannot contain spaces.
What I'm trying to do is make it more difficult for other admins (as root) to run a command against our Pass implementation (doc here : https://www.passwordstore.org/). It would still be possible, but I was hoping to turn a command like "pass rm $anyValueTheyInput" and alias that to, say "echo 'You can't do that'". Of course they're admins and they can change their aliases, but it would hopefully prevent accidental removal of passwords.
Is this possible in BASH? These will all be on RHEL or Centos boxes.
Aliasing whole commands complete with arguments is not possible in bash (if it's even possible in any UNIX shell at all).
What you can do is create a pass function that catches all the undesirable argument packs and forwards all other argument packs
to command pass:
pass()
{
if [ rm = "$1" ]; then
>&2 printf '%s\n' "You can't do that"
return 1
fi
#more checks... ?
#...
#forward the sanitized argument pack into the actual pass binary/script
command pass "$#"
}
This question already has answers here:
Why can't I specify an environment variable and echo it in the same command line?
(9 answers)
Closed 6 years ago.
Reducing what I'm trying to do to a simple example:
env temp=`pwd` echo "$temp"
I get this message:
temp: Undefined variable.
How do I make it work (in a shell-agnostic way)? I'm expecting the result of pwd to be printed.
My actual requirement uses a complicated expression in place of pwd, a script in place of "echo", and the variable $temp as an argument to that script.
Also, I want to set this variable only for this single command, and not for the whole shell (or any subsequent subshells).
How about something like this for sh and bash
(export temp=`pwd`; echo $temp)
And this for csh
csh -c 'setenv temp `pwd`; echo "$temp"'