LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 12-05-2019, 03:18 PM   #1
bmxakias
Member
 
Registered: Jan 2016
Posts: 254

Rep: Reputation: Disabled
Question sed escape characters issue


Hello

I am trying to to edit a file and change this line:

Code:
[ ${NETWORKING} = "no" ] && exit 0
to
Code:
[ "${NETWORKING}" = "no" ] && exit 0
i tried to use \ for some special characters and my command is:
Code:
sed -i "s|[ \${NETWORKING} = \"no\" ] && exit 0|[ \"\${NETWORKING}\" = \"no\" ] && exit 0|" /folder/file
But it doesn't work...
 
Old 12-05-2019, 05:52 PM   #2
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=15, FreeBSD_12{.0|.1}
Posts: 6,269
Blog Entries: 24

Rep: Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206
"Doesn't work" is not a very helpful description of what you see as a result.

Is all that context necessary and always identical?

If not, then assuming the test brackets to be sufficient context, this would safely work:
Code:
sed 's/[[] \${NETWORKING} = "no" []]/[ "${NETWORKING}" = "no" ]/' src.txt
If you do not actually need context beyond the immediate space characters this should work well enough too (GNU sed):
Code:
sed 's/ \(\${NETWORKING}\) / "\1" /' src.txt
It would be best to state the actual requirements and avoid the complications if not really necessary.
 
1 members found this post helpful.
Old 12-05-2019, 06:01 PM   #3
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 21,142

Rep: Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123
I hate escapes - this should be equivalent with a bit of luck
Code:
sed 's/${NETWORKING}/"&"/' src.txt
(and yes I know the back-reference isn't an escape ...)

Totally agree re the necessity for all the context - if needed use it as an address selection.

Last edited by syg00; 12-05-2019 at 06:03 PM. Reason: recalcitrant space char
 
2 members found this post helpful.
Old 12-05-2019, 06:11 PM   #4
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=15, FreeBSD_12{.0|.1}
Posts: 6,269
Blog Entries: 24

Rep: Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206
Quote:
Originally Posted by syg00 View Post
I hate escapes - this should be equivalent with a bit of luck
Code:
sed 's/${NETWORKING}/"&"/' src.txt
(and yes I know the back-reference isn't an escape ...)

Totally agree re the necessity for all the context - if needed use it as an address selection.
I included the surrounding spaces to avoid ending up with things like ""${NETWORKING}"", but agree that using an addressed context would be in order if needed rather than trying to squeeze it all into the regex.
 
Old 12-05-2019, 06:49 PM   #5
bmxakias
Member
 
Registered: Jan 2016
Posts: 254

Original Poster
Rep: Reputation: Disabled
My target is to add to ${NETWORKING} the "" like "${NETWORKING}" without changing anything else in the line.

Also using the full line i think is better because if the file has a second ${NETWORKING} then it will changed it also and i don't want that.

Is that the best solution for that scenario?

Code:
sed 's/[[] \${NETWORKING} = "no" []]/[ "${NETWORKING}" = "no" ]/' src.txt
All solutions above working great !

Thank you

Last edited by bmxakias; 12-05-2019 at 06:51 PM.
 
Old 12-05-2019, 07:24 PM   #6
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 21,142

Rep: Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123Reputation: 4123
Quote:
Originally Posted by bmxakias View Post
Is that the best solution for that scenario?
Somebody recently wanted to ban all "best of " questions ... this is Linux, hopefully everybody can find an option that suits. I would do it as
Code:
sed '/[[] \${NETWORKING} = "no" []]/ s/${NETWORKING}/"&"/' src.txt
Untested, but I reckon you shouldn't need to escape that $ either since you are using single quotes.

Last edited by syg00; 12-05-2019 at 07:27 PM. Reason: missing separator
 
2 members found this post helpful.
Old 12-05-2019, 08:07 PM   #7
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,872
Blog Entries: 1

Rep: Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871
A (hopefully) generic method:
Code:
From='[]^$\/*.'
To='Replaced'
SedMagic='s:[]\[\\\.\&*^$/]:\\&:g'
From1=$(echo "$From" | sed "$SedMagic")
To1=$(echo "$To" | sed "$SedMagic")
echo "AAA${From}AAA" | sed "s/$From1/$To1/"

Last edited by NevemTeve; 12-06-2019 at 01:01 AM.
 
1 members found this post helpful.
Old 12-06-2019, 04:32 AM   #8
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,009

Rep: Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193
As the code being changed appears to be bash, then the spaces around the changed item are required, so you should be able to just look for the item to change.
Here is another alternative:
Code:
sed -r 's/ (\$\{NETWORKING\}) / "\1" /' file
Here you do need the escapes shown as -r is extended regex so will use $ and {} for other things

Or without -r:
Code:
sed  's/ \(${NETWORKING}\) / "\1" /' file
One less escape here
 
Old 12-06-2019, 06:51 AM   #9
bmxakias
Member
 
Registered: Jan 2016
Posts: 254

Original Poster
Rep: Reputation: Disabled
Working great thank you !
 
Old 12-06-2019, 07:13 AM   #10
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,961

Rep: Reputation: 7330Reputation: 7330Reputation: 7330Reputation: 7330Reputation: 7330Reputation: 7330Reputation: 7330Reputation: 7330Reputation: 7330Reputation: 7330Reputation: 7330
you can also use . (dot) for special chars:
Code:
sed 's/^. ..NETWORKING. =/[ "${NETWORKING}" =/'
or something similar may work too.
 
1 members found this post helpful.
Old 01-01-2020, 09:50 AM   #11
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
I would re-think this a bit. The proper use of sed is to use the /address/ section to match the lines you want, then the command(s) following it (especially, but not limited to, 's///') to modify them.

So first figure out what makes the line unique and easy to target. It doesn't have to be the string you want to change. If, for example, it's the "exit 0", then use that for the address. sed would thus only modify lines containing it. You can use regex patterns, line numbers, line ranges, and more. Whatever works.

The commands following the address then target and modify the part of the matched lines that you want to change. Multiple commands can be grouped and/or nested with '{ ; }'. Here, I use a second, nested /address/ string to further filter the line:

Code:
#The input file. We want to change only the first line.#
$ cat infile.txt
[ ${NETWORKING} = "no" ] && exit 0
[ "${NETWORKING}" = "no" ] && exit 0
[ ${NETWORKING} = "no" ] && exit 1
[ Another unimportant ${NETWORKING} string ]
Code:
$ sed '/exit 0/ { /[^"]${N.*G}[^"]/ s/${N.*G}/"&"/ }' infile.txt
[ "${NETWORKING}" = "no" ] && exit 0
[ "${NETWORKING}" = "no" ] && exit 0
[ ${NETWORKING} = "no" ] && exit 1
[ Another unimportant ${NETWORKING} string ]
It first finds any line containing 'exit 0', then checks those lines for an unquoted '${N.*G}' string. If it finds one, it adds quotes around it. Notice how I simplified the regex down to (close to) the minimal phrase needed to get the match. It helps keep the code short and readable.

Actually, though, the following is slightly simpler. No nested commands are needed:

Code:
$ sed '/exit 0/ s|"\?\(${N.*G}\)"\?|"\1"|' infile.txt
[ "${NETWORKING}" = "no" ] && exit 0
[ "${NETWORKING}" = "no" ] && exit 0
[ ${NETWORKING} = "no" ] && exit 1
[ Another unimportant ${NETWORKING} string ]

or

$ sed -r '/exit 0/ s|"?(\$\{N.*G\})"?|"\1"|' infile.txt
[ "${NETWORKING}" = "no" ] && exit 0
[ "${NETWORKING}" = "no" ] && exit 0
[ ${NETWORKING} = "no" ] && exit 1
[ Another unimportant ${NETWORKING} string ]
We don't actually have to check for quotes, when we can simply replace them with themselves if they already exist.

Unfortunately, with this particular input, we either have to use sed in basic regex mode and escape the extended regex characters, or use extended regex mode (-r) and escape the special characters in the string. So to avoid the "picket fence" effect and help readability, I also changed 's///' to 's|||'. (Any ascii character not found in the pattern or the input string can be used as the delimiter.)


And finally, I found the sed FAQ to be very useful for learning how to use the full power of the command... although it is a bit out of date now:

http://sed.sourceforge.net/sedfaq.html
 
1 members found this post helpful.
Old 01-01-2020, 11:33 AM   #12
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
By the way, here's one more option that's just dawned on me. If the input allows it, you could use two 's' patterns and modify the start and end quotes separately, matching either quoting possibility. Just be sure to use strings long enough to match uniquely.

Code:
$ sed -r '/exit 0/ { s/"?\$\{N/"${N/ ; s/G}"?/G}"/ }' infile.txt
[ "${NETWORKING}" = "no" ] && exit 0
[ "${NETWORKING}" = "no" ] && exit 0
[ ${NETWORKING} = "no" ] && exit 1
Another unimportant ${NETWORKING} string
Be careful, though, when it comes to chaining commands. Later commands can potentially match and modify the output of earlier ones.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
shell: how to escape (or not escape) $ within an echo statement? Paul_N Linux - Newbie 2 04-05-2016 01:59 AM
bach scripting and escape characters... Bud-froggy Linux - Newbie 3 07-09-2004 04:55 PM
Escape Characters in linux shunraj Linux - Software 1 05-18-2004 03:21 PM
Handle escape characters in a string Helene Programming 7 05-01-2004 11:43 PM
escape characters not escaping BobNz Linux - Software 2 04-09-2004 03:34 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 06:56 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration