This question already has answers here:
Brace expansion with variable? [duplicate]
(6 answers)
Closed 5 years ago.
How do I expand a brace expansion that originally come from a string variables ? Note that the string variable is a requirement.
#!/usr/bin/env bash
TEXT_DIRS='opt/*/{doc,gtk-doc}'
My intention is reading a bash source from zsh, or maybe other language as well such as Perl or Python. Get the configuration from /etc/makepkg.conf, as below.
DOC_DIRS=(usr/{,local/}{,share/}{doc,gtk-doc} opt/*/{doc,gtk-doc})
It is all, for just, learning purpose.
Is that possible, to expand from string ?
The tricky thing here is that once Bash resolves the environment variable, it doesn't make another pass to process its contents again. You'd have to evaluate the content of the variable in another pass of the shell ( eg another shell command).
Here's one way to do that:
bash-4.4# TEXT_DIRS='/usr/*/{bin,src,lib}'
bash-4.4# bash -c ls\ $TEXT_DIRS
ls: /usr/*/src: No such file or directory
/usr/local/bin:
/usr/local/lib:
Here, I'm dynamically generating a shell command that I then evaluate to handle the 2nd expansion. (I took the liberty of changing the paths to something that would match on typical systems, so make sure to change it back if you try to test).
Dynamically generating code is always dangerous, if you can't trust the input. That's essentially how command injection attacks work. But use of eval in your own shell with trusted input is more or less "safe", though I rarely find myself using it unless in a contrived scenario like yours, or some of my own worse ideas.
Related
This question already has answers here:
How can I check if a program exists from a Bash script?
(39 answers)
Closed 6 years ago.
I've read in some bash FAQ a while ago (that I don't remember), that which should be avoided and command -v preferred.
Why is that so? What are the advantages, disadvantages of either one?
Well...
command is likely built in to your shell, and with the -v option will tell you how your shell will invoke the command specified as its option.
which is an external binary, located at /usr/bin/which which steps through the $PATH environment variable and checks for the existence of a file.
A reason to select the former over the latter is that it avoids a dependency on something that is outside your shell.
The two commands do different things, and you should select the one that more closely matches your needs. For example, if command is built in to your shell, command -v command will indicate this with its output (through the non-existence of path), but which command will try to point to a file on your path, regardless of how command would be interpreted by your shell.
This question already has answers here:
When to wrap quotes around a shell variable?
(5 answers)
Closed 3 years ago.
I have a command I want to run:
sbt "testOnly com.example.testClass"
which needs to be ran with the quotes. However, what I really want to do is be able to pass the argument in a variable, while keeping the quotes.
This does not work:
TEST_CMD="\"testOnly com.example.testClass\""
sbt $TEST_CMD
This does work:
TEST_CMD="\"testOnly com.example.testClass\""
eval sbt $TEST_CMD
I read http://mywiki.wooledge.org/BashFAQ/050 and now I understand why the first doesn't work, and I've also learned that eval can be insecure and should be avoided (this is just an internal Jenkins job, would it ever be an issue?).
Also in the article, it mentioned adding the command to an array first, so I tried:
args=("\"testOnly com.example.testClass\"")
sbt "${args[#]}"
but that also does not run correctly. What's the best way to do this? Is it really that bad to use eval in my case?
Quote the variable expansion rather than the assignment.
TEST_CMD="testOnly com.example.testClass"
sbt "$TEST_CMD"
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:
Echoing a tilde to a file without expanding it in Bash
(3 answers)
Pass a special variable (~ tilde) to Java program
(1 answer)
Closed 5 years ago.
I have a simple bash script that can accept arguments that it will be treating as text strings, nothing more.
If I give it ~, without quotes, then the home directory /home/users/me is what's parsed. Quote it, "~", it's fine. The character "~" is what I want, not the home path.
Is there any way I can ensure an un-quoted ~ is treated exactly as the character "~", not the home directory alias?
The bash shell is expanding the ~ on the command line before the argument is passed to your script.
There might be a bash option that you can change in your shell, but that would affect everything in your shell, which doesn't sound like what you want.
The short answer I think is no. There's nothing you can do in your script to change how the parent shell expanded any arguments before passing them to your script.
This question already has answers here:
How can I make bash treat undefined variables as errors?
(2 answers)
Closed 6 years ago.
I work with a lot of shell scripts that use bash variables. So, for example, I might have a script like this:
option1="-blah_blah"
option2="-yada_yada"
option3="-whatever"
...
option99="-something_else"
./myCommand "$option1 $option12 $option97 $option45"
I am constantly editing that last command to run various engineering tests. The problem is, sometimes I misspell a variable. In that case, Bash simply substitutes an empty string, and my command does the wrong thing silently.
Is there a way to have Bash throw an exception when I try to use a variable that is not defined?
Use:
set -e # Stop on error. I can't believe that this is not default.
set -u # Stop if trying to use un-initialized variables.