SH - Replace words in text value by variables [duplicate] - bash

This question already has answers here:
Bash expand variable in a variable
(5 answers)
Difference between single and double quotes in Bash
(7 answers)
Closed 1 year ago.
I have a problem that I am not able to solve, i need replace values of text variable in sh by the value of local variables.
Example:
~/Documents$ VERSION=1.0.0
~/Documents$ TEST='This is a test, VERSION: $VERSION'
~/Documents$ echo $TEST
This is a test, VERSION: $VERSION
I would like to transform the TEST string so that it uses the values ​​of the local variables.
I know I could change the ' ' to " " and that would work, but in my problem I get a literal string so I can't just do that.
Edit:
I am trying to convert a literal string into a string with replacement of values ​​by local variables in words beginning with "$", I could do this with a simple regex but I am looking for a better way, I believe that you should achieve this using only simple SH commands.

If TEST must be a literal string, you can use parameter substitution. These are bash docs, but it also works in sh:
${var/Pattern/Replacement}:
First match of Pattern, within var replaced with Replacement.
If Replacement is omitted, then the first match of Pattern is replaced by nothing, that is, deleted.
${var//Pattern/Replacement}: Global replacement. All matches of Pattern, within var replaced with Replacement.
For your given example, it would be ${TEST/\$VERSION/$VERSION}:
$ VERSION=1.0.0
$ TEST='This is a test, VERSION: $VERSION'
$ echo "${TEST/\$VERSION/$VERSION}"
This is a test, VERSION: 1.0.0
The first dollar sign is escaped so the Pattern is \$VERSION which becomes the literal string "$VERSION". Then its Replacement is $VERSION which gets interpolated as "1.0.0".

Related

What does the #*$ in a shell script's string interpolation do? [duplicate]

This question already has answers here:
What is the meaning of the ${0##...} syntax with variable, braces and hash character in bash?
(4 answers)
Closed 11 months ago.
I found the following code in a shell script, but I am unsure of what the test condition is evaluating for
if test "${SOME_VAR#*$from asdf/qwer}" != "$SOME_VAR"; then
echo "##zxcv[message text='some text.' status='NORMAL']";
fi
The combination #*$ does not mean anything special. There are three special symbols and each of them has its own meaning in this context.
${SOME_VAR#abc} is a parameter expansion. Its value is the value of $SOME_VAR with the shortest prefix that matches abc removed.
In your example, abc is *${from} asdf/qwer. That means anything * followed by the value of variable $from (which is dynamic and replaced when the expression is evaluated), followed by a space and followed by asdf/qwer.
All in all, if the value of $SOME_VAR starts with a string that ends in ${from} asdf/qwer then everything before and including asdf/qwer is removed and the resulting value is passed as the first argument to test.
Type man bash in your terminal to read the documentation of bash or read it online.

Quotes in makefile

this is my first post here (maybe more later ^^)
So, here we are :
I'm using Gitlab-CI, docker, makefile, firebase.
So in my Makefile :
firebase-deploy: ## Deploy the application
$(FIREBASE) deploy -m "$(comment)"
in my CI :
variables:
DOCKER_DRIVER: overlay2
MESSAGE: $CI_COMMIT_MESSAGE
deploy-firebase:
stage: deploy
script:
- make install
- make deploy comment="$MESSAGE"
The problem is actually, i have
docker-compose exec -T js node_modules/firebase-tools/lib/bin/firebase.js deploy -m "test ci ?
/bin/sh: syntax error: unterminated quoted string
So, as you can see, the double quote at the end is ... not here.
I tested a few things
\"Comment\"
\'Comment\'
"Comment\"
And more, but none of them work.
One thing interesting is that if i commit FROM gitlab.com it work as expected, but from my computer on push : nop.
Do you have any advice, or something to look for ?
Thanks!
If your commit message contains end of lines you cannot pass it to your script as it is. Try, maybe, to substitute end of lines by another character, e.g. -. Of course the way to do it depends on the shell that executes your CI scripts. If it is bash, for instance, the following should work:
make deploy comment="${MESSAGE//$'\n'/-}"
If you must also escape other characters you can chain substitutions. Example if you want to substitute end of lines and double quotes by - and ':
c="${MESSAGE//$'\n'/-}"; c="${c//\"/\'}"; make deploy comment="$c"
To learn more about these bash substitutions just type man bash and read section EXPANSION, sub-section Parameter Expansion. The parameter expansion I used is:
${parameter/pattern/string}
that replaces pattern by string in the value of variable parameter (in bash parlance parameter is another name for variable). When the pattern begins with a / all matches of pattern are replaced with string, else only the first match is replaced. So the first parameter expansion:
c="${MESSAGE//$'\n'/-}"
substitutes all end-of-line characters in the value of variable MESSAGE by - (more on $'\n' later) and assigns the result to variable c. Note the enclosing double quotes, they are needed because you can have spaces in the message. And the second:
c="${c//\"/\'}"
substitutes all " in the value of variable c by ' and assigns again the result to variable c.
In this case the most complicated is to put a end-of-line character in the first pattern, a double quote in the second and a single quotes in the second string. The $'string' construct is explained in the QUOTING section of the bash manual:
Words of the form $'string' are treated specially. The word expands to
string, with backslash-escaped characters replaced as specified by the
ANSI C standard.
So $'\n' is replaced by the end-of-line character. In the second pattern and string you just need to escape the double and single quotes with a backslash to have them interpreted literally.
Finally the 3 commands of this little shell script are chained by ;, the bash sequence operator. They are executed one after the other in the same bash invocation.

Variable Expansion when using variable within filename [duplicate]

This question already has answers here:
How to echo "$x_$y" in Bash script?
(4 answers)
When do we need curly braces around shell variables?
(7 answers)
Closed 3 years ago.
When using Bash I want to WGET multiple files from a server so I write a script with a For-loop that increments a counter to match the numbering of the files.
But I want to include the title of the file AND the number in which order the file appears (the "ID" of the file). So the the file has a URI of "example.com/files/hello_world.txt", with the ID of 42 and the title is "Hello World" when WGET it, the downloaded file should have the name "42_Hello_World.txt".
I tried the following code:
#! /bin/bash
# Init
index=42
title="Hello World"
# Replace blanks with underscore
title=${title/ /_}
# Concat fileName
fileName="$index_$title.txt"
echo $fileName
but the output is just "Hello_World.txt". When I change the order of $title and $index the output is "42.txt"
Can someone explain to me why this happens and how to solve it?
tl;dr
When using two or more variables in bash when evaluating a string only the last variable is "expanded". The first one is ignored. WHY???
_ is a valid character for an identifier, so $index_$title.txt is interpreted as the concatenation of two parameter expansions, $index_ and $title. To explicitly delimit the parameter name, use the full ${...} form:
fileName=${index}_$title.txt
The braces are not necessary for $title, because the following . cannot be interpreted as part of a parameter name (though the braces are certainly permitted: ${index}_${title}.txt).
Since index_ is not defined, $index_ expands to the empty string.
Yes. The explanation is the the _ character is a valid character in a variable name, so that your expressions are expanding the (undefined) variables $index_ and $title_ as empty strings. (The . is not a valid name character, so it terminates the 2nd name automatically.) Do this instead:
$ fileName="${index}_$title.txt"
$ echo $fileName
42_Hello_World.txt
$ echo "${title}_$index.txt"
Hello_World_42.txt
Could you please try following. This change should provide you your expected results. It is simple your variable "$index_$title.txt" is considered as you are concatenating 2 variables (index_ and title) so its better to quote _ like --> "_" and tell shell that it is a string.
index="42"
str="Hello World"
# Replace blanks with underscore
title=${str/ /_}
# Concat fileName
fileName=$index"_"$title".txt"
echo $fileName
In this nice url, you could see the last example of VALID variables(_ is there in the list):
https://bash.cyberciti.biz/guide/Rules_for_Naming_variable_name
The _ in the filename is not helping. _ is a valid variable character, and bash thinks that you want a variable called $index_ followed by $title, which isn't what you want. You can either:
Change the underscore character to an invalid variable name
Change to filename=$title"_"$index".txt" or
put brackets around $index
Hope this helps!
EDIT: You already have an answer here! How to echo "$x_$y" in Bash script?

UNIX Replace string without replacing space [duplicate]

This question already has answers here:
I just assigned a variable, but echo $variable shows something else
(7 answers)
Closed 5 years ago.
For string matching purposes I need to define a bash variable with leading spaces.
I need to define this starting from an integer, like:
jj=5
printf seems to me a good idea, so if I want to fill spaces up to 6 character:
jpat=`printf " %6i" $jj`
but unluckly when I am trying to recall the variable:
echo $jpat
the leading whitespaces are removed and I only get the $jj integer as it was.
Any solution to keep such spaces?
(This is equivalent to this: v=' val'; echo $v$v. Why aren't there leading and multiple spaces in output?)
Use More Quotes! echo "$jpat" will do what you want.
There is another issue with what you're doing: Command substitutions will remove trailing newlines. It's not an issue in the printf command you're using, but for example assigning jpat=$(printf " %6i\n" "$jj") would give you exactly the same result as your command.

Print the 4th column which contains wild character using shell script [duplicate]

I'm trying to figure out what I thought would be a trivial issue in BASH, but I'm having difficulty finding the correct syntax. I want to loop over an array of values, one of them being an asterisk (*), I do not wish to have any wildcard expansion happening during the process.
WHITELIST_DOMAINS="* *.foo.com *.bar.com"
for domain in $WHITELIST_DOMAINS
do
echo "$domain"
done
I have the above, and I'm trying to get the following output:
*
*.foo.com
*.bar.com
Instead of the above, I get a directory listing on the current directory, followed by *.foo.com and *.bar.com
I know I need some escaping or quoting somewhere.. the early morning haze is still thick on my brain.
I've reviewed these questions:
How to escape wildcard expansion in a variable in bash?
Stop shell wildcard character expansion?
Your problem is that you want an array, but you wrote a single string that contains the elements with spaces between them. Use an array instead.
WHITELIST_DOMAINS=('*' '*.foo.com' '*.bar.com')
Always use double quotes around variable substitutions (i.e. "$foo"), otherwise the shell splits the the value of the variable into separate words and treats each word as a filename wildcard pattern. The same goes for command substitution: "$(somecommand)". For an array variable, use "${array[#]}" to expand to the list of the elements of the array.
for domain in "${WHITELIST_DOMAINS[#]}"
do
echo "$domain"
done
For more information, see the bash FAQ about arrays.
You can use array to store them:
array=('*' '*.foo.com' '*.bar.com')
for i in "${array[#]}"
do
echo "$i"
done

Resources