I tried to use the bash string native manipulation for substituting string with my shell variables.
var1='123'
var2='2018-01-01'
var3='2018-01-02'
var4='myfunction('var1','var2','var3')'
var5=${var4/var1/$var1}
echo $var5
var5=${var5/var2/$var2}
echo $var5
var5=${var5/var1/$var3}
echo $var5
Expected output:
myfunction('123','var2','var3')
myfunction('123','2018-01-01','var3')
myfunction('123','2018-01-01','2018-01-02')
Actual output with jumbled strings:
myfunction('123','var2','var3')
myfunction('123','2018-01-01','var3')
')function('123','2018-01-01','2018-01-02
Here the last two characters shift at the beginning and I lose the first two characters of the string.
I can use SED for the same. But I am just trying to figure out why will the bash native string manipulation not work as expected. Is it because I am doing multiple substitutions ?
Thanks for your help.
I'm not able to replicate your output with my version (4.2.46) of bash:
david#localhost ~ % cat test.sh
var1='123'
var2='2018-01-01'
var3='2018-01-02'
var4='myfunction('var1','var2','var3')'
var5=${var4/var1/$var1}
echo $var5
var5=${var5/var2/$var2}
echo $var5
var5=${var5/var1/$var1}
echo $var5
and the output:
david#localhost ~ % bash test.sh
myfunction(123,var2,var3)
myfunction(123,2018-01-01,var3)
myfunction(123,2018-01-01,var3)
For what it's worth, I presume you also mean to replace var3 with $var3 in the final line of the script, rather than var1?
Additionally, setting $var4 with the below line would save the replacing of the strings, if that's not mandatory:
var4="myfunction('$var1','$var2','$var3')"
The single-quotes within the string value of var4 don't prevent the variable substitution, as they're within double-quotes already.
I was able to solve it by using dos2unix command on the file. The error was due to carriage return (CR) character at the end of var3 content.
Related
I'm creating a bash script and I need to be able to accept a string as the first parameter. This string may contain the $ character.
Script
#/bin/bash
pass="$1"
echo $pass
Output
root#server:/home# ./test.sh abc$xyz
abc
As you can see, the $ in the input is causing a problem because it's trying to interpret it as $xyz instead of a literal. Returning abc$xyz would be considered a successful response.
When you invoke:
$ ./test.sh abc$xyz
the shell parses that line by first looking for a variable named xyz. If that variable is unset, then $xyz expands to the null string and ./test.sh abc$xyz becomes ./test.sh abc. If you want to pass the literal string abc$xyz to your script, you should quote it to prevent the shell from doing any interpolation:
$ ./test.sh 'abc$xyz'
On an unrelated note, don't use the .sh suffix on your scripts. (https://www.talisman.org/~erlkonig/documents/commandname-extensions-considered-harmful/). But in this case, you shouldn't just remove the suffix, since test is also a terrible name for a script.
Enclose in single quotes characters or sections of the string to prevent the shell from interpreting them.
Alternatively, escape some special characters that are normally interpreted. Echo below shows what would be passed to a script:
echo Hi'\'myFriend => Hi\myFriend
echo Hi\$myFriend => Hi$myFriend
echo Hi\"myFriend\" => Hi"myFriend"
echo 'Hi "$myFriend"' => Hi "$myFriend"
echo "Hi $myFriend" => Hi
I was looking to try and figure out how trim a string in Bash, from the trailing end, once I hit a certain character.
Example: if my string is this (or any link): https://www.cnpp.usda.gov/Innovations/DataSource/MyFoodapediaData.zip
(I'll set that as my variable).
(I.e. if I echo $var it will return that link:)
I'm looking to use Bash, I'm guessing I will need to utilize sed or awk, but I want to trim, starting from the end until I see the first / (since the will be the file name) and strip that out.
So using that link, I'm trying to just get after the / so jus "MyFoodapediaData.zip" and set that to a different variable.
So in the end, if I echo $var2 (if I call it that) it will just return: MyFoodapediaData.zip"
I tried working with sed 's.*/" and that will start from the beginning until it finds the first slash. I was looking for the reverse order if possible.
You can use bash builtin parameter substitution for this:
$ var='https://www.cnpp.usda.gov/Innovations/DataSource/MyFoodapediaData.zip'
$ echo "$var"
https://www.cnpp.usda.gov/Innovations/DataSource/MyFoodapediaData.zip
$ var2=${var##*/}
$ echo "$var2"
MyFoodapediaData.zip
${var##*/} means "from the beginning of the value of the var variable, remove everything up to the last slash."
See parameter substitution in the manual
Whenever im trying to insert output with a line break into a variable for instance like this:
Hello
World
Once i do an echo command on the variable i get this:
"Hello World"
Why does it happen and how can i
keep the line break?
In bash, the easiest way to express a literal line break is with $'' syntax:
var=$'Hello\nWorld'
echo "$var"
Note that the quotes around $var are mandatory during expansion if you want to preserve linebreaks or other whitespace! If you only run
echo $var
...then even though a linebreak is stored in your variable, you will see
Hello World
on a single line, as opposed to
Hello
World
on two lines.
This happens because when you don't use quotes, the shell splits the expanded words on whitespace -- including newlines -- and passes each item created by that split as a separate argument. Thus,
echo "$var"
will pass a single string with the entire expansion of $var, whereas
echo $var
will run the equivalent of:
echo "Hello" "World"
...passing each word in the text as a separate argument to echo (whereafter the echo command re-joins its arguments by spaces, resulting in the behavior described).
Line breaks can be embedded in a string in any POSIX compatible shell:
$ str="Hello
> World"
$ echo "$str"
Hello
World
If you hit enter before closing the quotation marks, the shell knows you have not yet finished the quoted material, and prints the secondary prompt (>) and waits for you to finish the command.
I have looked at this question, but it does not cover my use case.
Suppose I have the variable foo which holds the four-character literal \x60.
I want to perform ANSI C Quoting on the contents of this variable and store it into another variable bar.
I tried the following, but none of them achieved the desired effect.
bar=$'$foo'
echo $bar
bar=$"$foo"
echo $bar
Output:
$foo
\x61
Desired output (actual value of \x61):
a
How might I achieve this in the general case, including non-printable characters? Note that in this case a was used just as an example to make it easier to test whether the method worked.
By far the simplest solution, if you are using bash:
printf %b "$foo"
Or, to save it in another variable name bar:
printf -v bar %b "$foo"
From help printf:
In addition to the standard format specifications described in printf(1)
and printf(3), printf interprets:
%b expand backslash escape sequences in the corresponding argument
%q quote the argument in a way that can be reused as shell input
%(fmt)T output the date-time string resulting from using FMT as a format
string for strftime(3)
There are edge cases, though:
\c terminates output, backslashes in \', \", and \? are not removed,
and octal escapes beginning with \0 may contain up to four digits
The following works:
eval bar=\$\'$x\'
The command bar=$'\x61' has to be constructed first, then eval evaluates the newly built command.
I just found out that I can do this. Edited based on comments.
bar=$( echo -ne "$foo" )
The best method I know is
y=$(printf $(echo "$foo"|sed 's/%/%%/g'))
As mentioned in the comments, this trims trailing newlines from $foo. To overcome this:
moo=$(echo "${foo}:end"|sed 's/%/%%/g')
moo=$(printf "$moo")
moo=${moo%:end}
# the escaped string is in $moo
echo "+++${moo}---"
Since bash 4.4 there is a variable expansion to do exactly that:
$ foo='\x61'; echo "$foo" "${foo#E}"
\x61 a
To set another variable use:
$ printf -v bar "${foo#E}"; echo "$bar"
a
Sample of conversion via shell. Problem, the code is octal using \0nnn and hexdecimal (not on all shell) using \xnn (where n are [hexa]digit)
foo="\65"
print "$( echo "$foo" | sed 's/\\/&0/' )"
5
with awk, you could certainly convert it directly
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.