Bash script doesn't evaluate variable in filename [duplicate] - linux

This question already has answers here:
What is the difference between ${var}, "$var", and "${var}" in the Bash shell?
(7 answers)
Closed 5 years ago.
I have a bash script which creates a backup of my folder. It should name the tar gz file using a version number but it doesn't:
#!/bin/bash
ver='1.2.3'
tar czf $ver_myfolder.tar.gz .
Expected output:
1.2.3_myfolder.tar.gz
Actual output:
_myfolder.tar.gz
If I append the variable like this:
#!/bin/bash
ver='1.2.3'
tar czf myfolder-$ver.tar.gz .
It works

You should use ${var} here since you are appending underscore after it which is considered a valid character for variable names. Due to that fact shell doesn't know whether you're expanding variable name $ver or $ver_myfolder:
ver='1.2.3'
tar czf "${ver}_myfolder.tar.gz" .
Since $ver_myfolder is unset, you get an empty value.

Because the underscore is a valid character for a variable name, you should use braces to explicitly specify the range of your variable:
${ver}_myfolder.tar.gz
^ ^
Without braces, Bash will actually try to parse
${ver_myfolder}.tar.gz
For your edited question, it is because the dot is not a valid character for a variable name, so Bash will not attempt to parse the dot into the name lookup. Even if you put it into braces, a variable name containing a dot is still invalid:
$ echo ${ver.}
bash: ${ver.}: bad substitution
$ ver.=1.2.3
ver.=1.2.3: command not found

Related

How do I pass quoted shell variables as arguments correctly? [duplicate]

This question already has answers here:
Why does shell ignore quoting characters in arguments passed to it through variables? [duplicate]
(3 answers)
Variable containing multiple args with quotes in Bash
(4 answers)
Closed 10 months ago.
As part of a build pipeline I have a shell script that zips up a directory. I want to use a variable to define which patterns should be ignored.
I'm doing something like this:
IGNORE='"*.md" "some-folder/*"'
zip -x $IGNORE -r my-zip.zip ./*
Which doesn't appear to work, the ignored files and folders are still included in the zip archive.
This does work if I create the command and then pipe it through to sh though, so I'm confident that the variable contains the correct values:
echo "zip -x $IGNORE -r my-zip.zip ./*" | sh
I think it might be something to do with the quotes, since this works as expected without them. However this fails as soon as I attempt to add more than 1 pattern to IGNORE.
IGNORE=*.md
zip -x $IGNORE -r my-zip.zip ./*
What am I missing in order to be able to pass these patterns correctly quoted?
Edit: this does also not appear to work as an array, as suggested by this question.
IGNORE='"*.md" "some-folder/*"'
EXCLUDE=($IGNORE)
zip -x ${EXCLUDE[#]} -r my-zip.zip ./*

BASH "for ... in ..." don't work with variables [duplicate]

This question already has an answer here:
In bash, how do I expand a wildcard while it's inside double quotes?
(1 answer)
Closed 2 years ago.
I want to write a simple script that does something for every file in user-defined directory. Here's a script that works for predefined directory:
for file in mydir/*; do
printf "$file"
done
Here's similar script that prints name of each file in the directory defined by variable:
for file in "$nicedir*"; do
printf "$file"
done
This second script don't work. Of course, I remembered about slash at the end of the path. (I passed ./ as the argument instead of just .)
Pathname expansion doesn't happen in quoted strings. Keep the wildcard outside of the quotes:
for file in "$nicedir"* ; do
printf '%s\n' "$file"
done
The final slash is usually not required in paths, so you'll more often see
for file in "$nicedir/"*
# or equivalent
for file in "$nicedir"/*

bash: initiate command inside of a string. - using sed [duplicate]

This question already has answers here:
How to replace a value with the output of a command in a text file?
(2 answers)
Closed 5 years ago.
my sed input is as follows:
sed 's/ListenAddress=.*/ListenAddress= $hostname/' nodemanager.properties
I am trying to run this against a Linux server and replace ListenAddress={current_value} with ListenAddress={hostname_of_server}
I need to know how to run the hostname command and have that output be reflected at the end of ListenAddress=
Thanks
If you wish your bash variables to reflect inside the sed script use, double quotes. The same is valid for command substitution. So you should be doing
sed "s/ListenAddress=.*/ListenAddress= $(hostname)/" nodemanager.properties
Since thevariable expansion takes place, you need to be careful about certain situations where $ appear as a sed attribute. For example if you're applying the above command only to the last line of the file, then do
sed "\$s/ListenAddress=.*/ListenAddress= $(hostname)/" nodemanager.properties
Note the $ before s command is escaped meaning that it is literal $ supplied to the script.

File read not interpreting Environment variables [duplicate]

This question already has an answer here:
Expand ENV variable of a string, run command and store in variable?
(1 answer)
Closed 6 years ago.
When I try to read a file which contains a environment variable HOSTNAME.
It is not interpreting its value while reading the file.
For example, if my hostname is linux1.com.
When I try to read a sample file(Test.txt) below
/var/log/$HOSTNAME
using the code below
while read line
do
ls -l $line
done < Test.txt
I am expecting it to interpet the $HOSTNAME variable and print it. But it is not working. It is directly doing ls -l /var/log/$HOSTNAME, instead of
ls -l /var/log/linux1.com
The same command is intrepreting the hostname when I run this command in shell.
Any leads on this is highly appreicated.
Thanks.
Parameter expansion is not recursive. When $line is expanded, its value is subject to pathname expansion (globbing) and word-splitting, but not further parameter expansions.

Why do I use double quotes in shell scripts [duplicate]

This question already has answers here:
When to wrap quotes around a shell variable?
(5 answers)
Closed 6 years ago.
I understand the usage single quote and double quote.
but I don't know situation need to double quotes in the script.
there is no diff that statements
$ echo hello world! $1
$ echo "hello world! $1"
please show me diff between normal and double quotes.
Let's consider a directory with these files:
$ ls foo*
foo111.txt foo11.txt foo1.txt
Let's consider a minor variation on your script:
$ cat script
#!/bin/sh
echo No quotes $1
echo "Double quotes $1"
Now, let's run it:
$ bash script "foo*"
No quotes foo111.txt foo11.txt foo1.txt
Double quotes foo*
As you can see, the results are completely different. Without the double quotes, pathname expansion is performed.
To illustrate another difference:
$ bash script "long space"
No quotes long space
Double quotes long space
With double quotes, the long space between words is preserved. Without it, all contiguous whitespace is replaced with a single blank. This is an example of word splitting.
An example might demonstrate the use
To accommodate string with spaces
var=file name # Not the intended effect.
file is stored in a var and name is taken by shell as a separate cmd which gives you an error.
To prevent word splitting
var="file name"
cp $var newfile
Here $var expands to file name and in effect, the command would become
cp file name newfile
and cp would take file and name as 2 source files and newfile as the destination directory which gives you the error:
cp: target 'newfile' is not a directory
If there really exists a directory named 'newfile', it will give error:
cp: cannot stat 'file': No such file or directory
cp: cannot stat 'name': No such file or directory
The correct method is
cp "$var" newfile
In this case, the fully expanded $var is considered a single string.

Resources