LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   sed script and sed command line give different results (https://www.linuxquestions.org/questions/linux-newbie-8/sed-script-and-sed-command-line-give-different-results-4175720645/)

no-windose 01-08-2023 02:02 AM

sed script and sed command line give different results
 
I want to replace the 3rd occurrence of a single pipe "|" in some text with a double pipe "||". I can do it with a simple command line but not with a script. May I ask why?
Code:

$ cat sample.txt
field1 | field2 | field4 | field5 | field6
$ sed 's/ '\|' / \|\| /3' sample.txt
field1 | field2 | field4 || field5 | field6

$ cat sed-script
s/ '\|' / \|\| /3
$ sed -f sed-script sample.txt
field1 | field2 | field4 | field5 | field6


Turbocapitalist 01-08-2023 02:21 AM

One way is to count to the third pipe:

Code:

sed -r -e 's/^(([^|]+\|){3})\|/\1/'
perl -p -e 's/^(([^|]+\|){3})\|/$1/;'

There is probably a more efficient pattern.

no-windose 01-08-2023 02:57 AM

Thanks Turbocapitalist but I would like to know why my own script does not work. Also I would prefer to avoid the -r option because all my other sed scripts are not compatible with it. I haven't tried perl for the same reason: all my scripts are with sed already. Anyway the sed command you suggest does not seem to work:
Code:

$ sed -r -e 's/^(([^|]+\|){3})\|/\1/' sample.txt
field1 | field2 | field4 | field5 | field6


pan64 01-08-2023 03:30 AM

you ought to use set -xv in this case:
Code:

$ set -xv
$ sed 's/ '\|' / \|\| /3' sample.txt
sed 's/ '\|' / \|\| /3' sample.txt
+ sed 's/ | / \|\| /3' sample.txt  # <<< this is the real sed script after command line evaluation

So this is how your command interpreted by the shell. When you use sed -f sed-script bash will not evaluate (or modify) that script, so you need not escape special chars.
From the other hand you don't need to escape anything at all.
Code:

echo 'field1 | field2 | field4 | field5 | field6' | sed 's/ | / || /3'
works too, and actually that sed-script is the same:
Code:

s/ | / || /3

MadeInGermany 01-08-2023 05:20 AM

The embedded sed script is in a 'string'. After a ' the following ' ends it.
Code:

sed 's/ '\|' / \|\| /3' sample.txt
The shell passes it dequoted to sed:
Code:

s/ | / \|\| /3
This is different from your pure sed code
Code:

s/ '\|' / \|\| /3
The | character is not special in a BRE (grep, sed) but it is in an ERE (grep -E, sed -r). And it should never be escaped in the replacement string.
Code:

sed 's/ | / || /3' sample.txt
Code:

sed -r 's/ \| / || /3' sample.txt
Code:

#!/bin/sed -f
s/ | / || /3

Code:

#!/bin/sed -rf
s/ \| / || /3


syg00 01-08-2023 05:31 AM

Quote:

Originally Posted by MadeInGermany (Post 6403018)
The | character is not special in a BRE (grep, sed) but it is in an ERE (grep -E, sed -r).

You can have lots of fun with that character in regex - one of those "corner cases" that people gloss over ... :p

no-windose 01-08-2023 02:24 PM

Thank you all.

pan64 01-09-2023 04:19 AM

if you wish to say thanks just click on yes


All times are GMT -5. The time now is 06:07 PM.