I have a pretty strange problem with sed, if I do with this:
[root#Camel ~]-> sed -i 's/TLRAGENT_IP=.*/TLRAGENT_IP='"${HOST_IP}"'/' ~user/.bash_profile
it's fine. But if I try the following:
[root#Camel ~]-> CONF_FILE="~user/.bash_profile"
[root#Camel ~]-> sed -i 's/TLRAGENT_IP=.*/TLRAGENT_IP='"${HOST_IP}"'/' ${CONF_FILE}
sed: can't read ~user/.bash_profile: No such file or directory
also tried to quote the variable:
[root#Camel ~]-> sed -i 's/TLRAGENT_IP=.*/TLRAGENT_IP='"${HOST_IP}"'/' "${CONF_FILE}"
sed: can't read ~user/.bash_profile: No such file or directory
couldn't figure out where went wrong, please advise.
Shell's version is 3.2.25(1)-release.
from man bash /EXPANSION
EXPANSION
Expansion is performed on the command line after it has been
split into words. There are seven kinds of expansion per-
formed: brace expansion, tilde expansion, parameter and
variable expansion, command substitution, arithmetic expan-
sion, word splitting, and pathname expansion.
The order of expansions is: brace expansion, tilde expan-
sion, parameter, variable and arithmetic expansion and com-
mand substitution (done in a left-to-right fashion), word
splitting, and pathname expansion.
The parameter and variable expansion comes after tilde expansion
To have tilde expansion, this can be done at variable definition
CONF_FILE=~user/.bash_profile
instead of
CONF_FILE="~user/.bash_profile"
Related
I have two text files identical to each other a.text and b.text with the same content.
Content of a.text and b.text
abcd
target
efgh
Can anyone explain why one of the commands work but not the other and if there is a way of making it work?
Output of command 1
grep "target" {a,b}.text
>>a.text:target
b.text:target
Output of command 2
file="{a,b}.text"
grep "target" $file
>>grep: {a,b}.text: No such file or directory
Happy if someone can point me to a location where I can read more about this as well. I can only assume that when storing it as a variable it explicitly looks for a file called {a,b}.text although, what I am not as sure about is why and what leads to that.
As user1934428 said, brace expansion happens before parameter expansion. Quoting from the bash manual:
Expansion is performed on the command line after it has been split into words. There are seven kinds of expansion performed: brace expansion, tilde expansion, parameter and variable expansion, command substitution, arithmetic expansion, word splitting, and pathname expansion.
The order of expansions is: brace expansion, tilde expansion, parameter, variable and arithmetic expansion and command substitution (done in a left-to-right fashion), word splitting, and pathname expansion.
To get this to work you can store the file names in an array. Arrays can hold multiple file names without being subject to quoting or expansion issues that plague normal string variables.
files=({a,b}.text)
grep "target" "${files[#]}"
This works because {a,b} is now evaluated when the variable is assigned, rather than when it is expanded.
In the first case, you have a brace-expansion. In the second case, you are searching a file with the literal name {a,b}.text. The reason is that in bash, brace expansion happens before parameter expansion.
I'm a newbie to shell scripting and I have the following problem:
If I enter into the shell
cat << EOF
'"$10^2$"'
EOF
I expected (and wanted) to get something like
"$10^2$"
but actually it used parameter substitution and I got
'"0^2"'
Why does it parameter substitution (I used single quotes!?)? And how can I get the desired output?
Escape the dollar sign:
cat << EOF
'"\$10^2$"'
EOF
OUTPUT:
"$10^2$"
Otherwise $1 is being expanded by shell and shows output as empty string only only and you get output as '"0^2$"'
UPDATE: Otherwise use this form of heredoc to avoid variable expansion:
cat <<'EOF'
'"$10^2$"'
EOF
'"$10^2$"'
Explanation: As per man bash:
<<[-]word
here-document
delimiter
No parameter expansion, command substitution, arithmetic expansion, or pathname expansion is performed on word. If any characters in word are quoted, the
delimiter is the result of quote removal on word, and the lines in the here-document are not expanded. If word is unquoted, all lines of the here-document
are subjected to parameter expansion, command substitution, and arithmetic expansion. In the latter case, the character sequence \ is ignored, and
\ must be used to quote the characters \, $, and `.
See bolded text above for the explanation why variables got expanded in your example but not when I used quoted 'EOF'.
I have a little problem with my bash script.
#!/bin/bash
ex xxx.html << "HERE"
1,$s/\(foo\)/$1\1/
wq
HERE
This is just a little piece of my script. when I run it this is the output.
$1foo
Any way to fix this so the $1 will be the argument given to the script?
Thanks!
Try replacing "HERE" with HERE (unquoted). Also 1,$s becomes 1,\$s.
Here Documents
This type of redirection instructs the shell to read input from the
current source until a line containing only delimiter (with no trailing
blanks) is seen. All of the lines read up to that point are then used
as the standard input for a command.
The format of here-documents is:
<<[-]word
here-document
delimiter
No parameter expansion, command substitution, arithmetic expansion, or
pathname expansion is performed on word. If any characters in word are
quoted, the delimiter is the result of quote removal on word, and the
lines in the here-document are not expanded. If word is unquoted, all
lines of the here-document are subjected to parameter expansion, com-
mand substitution, and arithmetic expansion. In the latter case, the
character sequence \<newline> is ignored, and \ must be used to quote
the characters \, $, and `.
If the redirection operator is <<-, then all leading tab characters are
stripped from input lines and the line containing delimiter. This
allows here-documents within shell scripts to be indented in a natural
fashion.
Bash manual.
Remplace "HERE" with HERE (without quotes) and remplace 1,$ with 1,\$ or %
You could write your script as follows:
#!/bin/bash
ex xxx.html <<-HERE
%s/foo/$1&/
x
HERE
Although you could also build a smaller script:
#!/bin/bash
sed -i "s/foo/$1&/g" xxx.html
Try this.
#!/bin/bash
(echo '1,$s/\(foo\)/'"$1"'\1/'; echo 'wq') | ex xxx.html
That's 1,$s/\(foo\)/ in single quotes, adjacent to $1 in double quotes (so the shell substitutes the parameter), adjacent to \1/ in single quotes.
I get tripped up on the sequence of substitutions shell does. I understand shell will do variable substitution before file substitution, which is done before the command line is parsed. Shell can do many different substitutions. I just don't know which is done first, second, third, and so forth. Does anyone have a precedence chart of shell substitutions?
From man (1) bash:
The order of expansions is: brace expansion, tilde expansion, parameter, variable and arithmetic expansion and command substitution (done in a left-to-right fashion), word splitting, and pathname expansion.
I am writing a simple bash script and wanted to display all the items in a a particular directory. I tried doing the following:
desktop="~/Desktop/testr/"
echo $desktop
echo `ls $desktop`
However I keep getting the output:
~/Desktop/testr/
ls: ~/Desktop/testr/: No such file or directory
But when I run ls from the terminal, I can see the items. I suspect that the problem is that the ~ is not getting expanded but I thought that the double quotes would have taken care of that.
Thanks for your help!
This is because within quoted strings there is no tilde expansion and tilde expansion comes before parameter substitution in the echo line.
The sequence of expansions is:
Tilde expansion
parameter expansion
command substitution
arithmetic expansion
Field splitting
Pathname expansion
Quote removal
See the POSIX Shell Specification on Word Expansions for the gory details.