Reputation: 751
I have the following file ~/hello.txt
:
qwe asd qwe
bash "$HOME/byobu.sh"
bash "$HOME/byobu.sh"
# asd yxc asd
How can I replace a string beginning with a newline and a variable so that the file will result in:
qwe asd qwe
# bash "$HOME/byobu.sh"
bash "$HOME/byobu.sh"
# asd yxc asd
i.e. replace the first occurrence of the second string to its commented version. Trying the following commands:
byobu_line='bash "$HOME\/byobu.sh"'
sed -i '0,/\n'"$byobu_line"'/ s/\n'"$byobu_line"'/\n# '"$byobu_line"'/' ~/hello.txt
leaves the file untouched.
Solutions without sed
are accepted as well.
Note: the newline \n
here is necessary to be matched and replaced by itself because, if I run it a second time without it, it will lead to the unwanted result
qwe asd qwe
# # bash "$HOME/byobu.sh"
bash "$HOME/byobu.sh"
# asd yxc asd
Upvotes: 3
Views: 243
Reputation: 133498
Could you please try following, if you are ok with awk
.
byobu_line='bash "$HOME/byobu.sh"'
awk -v var="$byobu_line" '$0 == var && !found{$0="#"$0;found=1} 1' Input_file
EDIT: To avoid expansion of $HOME
I have come up with a thought, could you please try following, will add explanation in sometime(after having my dinner :) ).
Here is the Input_file:
cat file
qwe asd qwe
bash "$HOME/byobu.sh"
bash "$HOME/byobu.sh"
# asd yxc asd
Here is the script:
cat file.ksh
HOME="/home/ubuntu" ##Setting value for testing purposes, to make sure they are NOT getting expanded.
byobu_line='bash "$HOME/byobu.sh"'
byobu_line_new=$(echo "${byobu_line//$/}")
awk -v var="$byobu_line_new" 'BEGIN{sub(/HOME/,"$&",var)} $0 == var && !found{$0="#"$0;found=1} 1' Input_file
Please append > temp && mv temp Input_file
in my awk
code's line above and it will save output into Input_file itself.
Explanation: EDIT code what I am doing is, I am using shell's parameter expansion to create variable named byobu_line_new
which DO NOT have $
. Now when same variable is passed to awk
in var
variable and before reading Input_file in BEGIN
section I again used substitution to get $
before HOME. This is only to remove affect of expansion of variable(as a work around).
For awk
code: I have passed shell variable byobu_line_new
to awk
variable named var
, then in BEGIN
section I am substituting HOME with $HOME
in variable(which I previously removed mentioned above), now when Input_file is getting read checking condition if $0
(current line) is equal to var
and variable found
is NOT SET(which will happen only for very first match, because when a match of var==$0
is found means your shell variable is found in line then setting variable found
to 1, so next time this condition will NOT be TRUE). Then mentioning 1
will print edited/non-edited lines from Input_file(since awk
works on method of pattern and then action, I am making condition TRUE by mentioning 1 and no action given so by default print of line will occur).
Upvotes: 5
Reputation: 84561
Your attempt at the use of sed
was very close. The use of the form 0,/match/s/find/replace/
was correct, but you need to alter it slightly as:
sed '0,/^bash\ "\/home\/david\/byobu.sh"$/s/^bash\ "\/home\/david\/byobu.sh"$/# bash\ "\/home\/david\/byobu.sh"$/' file
The use of the 0,addr2
causes sed
to start out in the "matched first address" state
so when addr2
is found the expression will be at the end of its range, make the substitution once and then not match again having the effect of matching the first occurrence only.
You were simply mistaken in believing you needed to search for a line beginning with '\n'
. That isn't the way sed
works. Lines don't begin with '\n'
characters.
In the expression bash "/home/david/byobu.sh"
, you should anchor the beginning and end with '^'
and '$'
, respectively so you do not also match a lesser included substring of a larger line.
For the substitution, you simply need to insert "# "
at the beginning of the line with s/^bash\ "\/home\/david\/byobu.sh"$/# bash\ "\/home\/david\/byobu.sh"$/
. For the same reason you need to anchor the 0,/addr2/
term, you should fully describe and anchor the substitution terms as well.
Putting it altogether, you could do:
$ sed '0,/^bash\ "\/home\/david\/byobu.sh"$/s/^bash\ "\/home\/david\/byobu.sh"$/# bash\ "\/home\/david\/byobu.sh"$/' file
qwe asd qwe
# bash "/home/david/byobu.sh"
bash "/home/david/byobu.sh"
# asd yxc asd
Which provides your expected results.
Upvotes: 3