How to print a variable which contains '$' in it in bash? [duplicate] - bash

This question already has answers here:
Difference between single and double quotes in Bash
(7 answers)
Closed 7 years ago.
I'm writing a bash script which contains a variable called "line", and I want to print it's content.
The problem is that the "line" variable is a string which contains the '$' char.
My question is how can I print the value of the "line" variable, without replacing the dollars with variables.
For example, if "line" is containing "a$#gz%^", this code:
echo $line
Will output this:
a0gz%^
And if I'll put the '$line' in single quotes, it will just print '$line':
echo '$line'
$line
Hope you'll be able to help.

You have to quote the string when you assign it to the variable:
line='a$#gz%^'
Otherwise, $# is expanded before the assignment.
To output the literal variable, use double quotes
echo "$line"
It looks confusing at first, but it is actually pretty simple (at least to a first approximation):
string with $line in it -- never what you want, particularly if it includes a variable. OK if there is no variable and the string is just letters and numbers (and pattern characters if you want them to be expanded). Expands variables, splits into words, expands filename patterns.
"string with $line in it" -- expands variables, but doesn't word split or expand filename patterns
'string with $line in it' -- literal string, just the characters between the apostrophes

You can store string in variable having special characters by giving escape sequence like below -
line="a\$#gz%^"
And then echo $line

Related

different interpretation of varialble as pattern [duplicate]

This question already has answers here:
Regex stored in a shell variable doesn't work between double brackets
(2 answers)
bash regex with quotes?
(5 answers)
Closed 1 year ago.
I would like someone to clarify this because I don't understand it.
Here is a sample code, that tests an argument if it is numeric or not (integer)
#/bin/env bash
pattern="^[+|-]?[0-9]+$"
[[ "$1" =~ "$pattern" ]] && echo "1:number" || echo "1:NOT number"
[[ "$1" =~ $pattern ]] && echo "1:number" || echo "1:NOT number"
it is advisable to quote always the variables, but here, if you make the test with this simple script with various inputs, you will see that if you enter a number, the quoted pattern variable returns an erroneous result (first test)
Why is that?
thanks in advance for anyone who will take the trouble to explain this to me.
Finally, sorry if that is already answered but I haven't found that particular one.
It's normally advised to quote all variables. But [[ ]] is a special operator, it parses its contents differently.
You don't need to quote variables inside double square brackets, because it doesn't do word splitting or filename expansion. But there's no harm in quoting most variables.
However, the pattern operand to =~ is treated very specially. Any part of it that's quoted is treated as a literal, not a regular expression pattern. So when you write "$pattern" it no longer does a regular expression match, it just searches for the actual characters in $pattern in $1.

Split string into array in shell script based on regex delimiter [duplicate]

This question already has answers here:
Split a string only by spaces that are outside quotes
(4 answers)
Closed 2 years ago.
I have a string variable called JAVA_OPTS with various parameters in shell script.
-Dmaven.repo.local=/home/wangc/.m2/repository -Dtestparameter="some spaces" --add-exports=java.base/sun.nio.ch=ALL-UNNAMED
I'd like to split it into an array based on spaces, but not the space defined in escaped double quotes. For example I'd like to see an array with 3 elements:
-Dmaven.repo.local=/home/wangc/.m2/repository
-Dtestparameter="some spaces"
--add-exports=java.base/sun.nio.ch=ALL-UNNAMED
I have tried
IFS=' ' read -r -a array <<< "$JAVA_OPTS"
But it can't tell the different space between double quotes, and return a four elements array as:
-Dmaven.repo.local=/home/wangc/.m2/repository
-Dtestparameter="some
spaces"
--add-exports=java.base/sun.nio.ch=ALL-UNNAMED
Why do you require a regex solution? Getting the shell itself to parse this is significantly easier.
array=(-Dmaven.repo.local=/home/wangc/.m2/repository -Dtestparameter="some spaces" --add-exports=java.base/sun.nio.ch=ALL-UNNAMED)
Detouring the values via a string variable $JAVA_OPTS is precisely the wrong thing to do here, and makes the problem signicicantly harder.

bash: What are the purposes of the two colons in echo ${addr:$i:2}?

Can someone explain the meaning of the following bash script? I am mainly confused about the echo usage. What are the purposes of the two colons?
for addr in $#; do
for i in $(seq 8 -2 2); do echo -ne "\x${addr:$i:2}"; done
done
You have
echo -ne "\x${addr:$i:2}"
The -n option instructs echo to not output a newline at the end of the line.
The -e instructs echo to treat the \x in its string as a prefix for an "eight-bit character whose value is given as a 2-character hexadecimal number" (adapted from the manual).
The ${addr:$i:2} is "substring expansion". It will give you the 2-character substring from offset $i in the string "$addr" (which will probably be the hexadecimal number that is going to be converted into that eight-bit character).
EDIT: See comments from user #CharlesDuffy below about the standard (non-)conformance of the echo built-in command in bash, the options that are likely to break this code if they are set, and an alternative solution using printf that will make the code much more robust would want to update it.
It's a feature of Bash string substitution, not of echo. The notation ${var:start:length} extracts a substring of the variable var starting at character start and containing a substring of length.
The character : is called colon; the semicolon looks like this: ;
In here the ${addr:$i:2} extracts the chars in string $addr from postion $i up to $i+2
The index -2 makes no sense to me as it will always return the full string if calles with a negative start position.
Finally it will output:
Chars 8 up to 10 and 2 up to 4 for all words that are passed as an argument.

In shell scripting, how do I ensure all characters in a variable are passed literally?

Say I have this command:
printf $text | perl program.pl
How do I guarantee that everything in the $text variable is literally? For example, if $text contains hello"\n, how do I make sure that's exactly what gets passed to program.pl, without the newline or quotation mark (or any conceivable character) being interpreted as a special character?
Quotes!
printf '%s' "$text" | ...
Don't ever expand variables unquoted if you care about preserving their contents precisely. Also, don't ever pass a dynamic string as a format variable when you want it to be treated as literal data.
If you want backslash sequences to be interpreted -- for instance, the two-character sequence \n to be changed to a single newline -- and your shell is bash, use printf '%b' "$text" instead. If you want byte-for-byte accuracy, %s is the Right Thing (and works on any POSIX-compliant shell). If you want escaping for interpretation by another shell (which would be appropriate if, say, you were passing content as part of a ssh command line), then the appropriate format string (for bash only) is %q.

place a multi-line output inside a variable

I'm writing a script in bash and I want it to execute a command and to handle each line separately. for example:
LINES=$(df)
echo $LINES
it will return all the output converting new lines with spaces.
example:
if the output was supposed to be:
1
2
3
then I would get
1 2 3
how can I place the output of a command into a variable allowing new lines to still be new lines so when I print the variable i will get proper output?
Generally in bash $v is asking for trouble in most cases. Almost always what you really mean is "$v" in double quotes:
LINES="$(df)"
echo "$LINES"
No, it will not. The $(something) only strips trailing newlines.
The expansion in argument to echo splits on whitespace and than echo concatenates separate arguments with space. To preserve the whitespace, you need to quote again:
echo "$LINES"
Note, that the assignment does not need to be quoted; result of expansion is not word-split in assignment to variable and in argument to case. But it can be quoted and it's easier to just learn to just always put the quotes in.

Resources