sed replacement \1 not working - sed

Typing the following on the command line:
echo happy | sed -r s/\([p]\)\([p]\)/*\1*\2*/
I expect the following result:
ha*p*p*y
Instead, this is the result:
ha*1*2*y
I am using Ubuntu 12.04.3 LTS (GNU/Linux 3.2.0-53-generic x86_64)
The shell is -ksh
sed is 4.2.1 December 2010
The -r option allowed me to use \( and \). I thought it would also enable \1 and \2 but that doesn't seem to be the case. Is there another option I'm overlooking?

When typed on the command line, the shell is interpreting some of your backslash characters, so sed never sees them.
Instead, try one of these. Notice the single quotes which preserves the literal backslash characters.
echo happy | sed -r 's/([p])([p])/*\1*\2*/'
or
echo happy | sed 's/\([p]\)\([p]\)/*\1*\2*/'

you don't need -r just use
echo happy | sed 's/\(p\)\([p]\)/*\1*\2*/'

Related

Replacing = with in using sed

I have a string like below
abc="where session = '001122' and indicator = 'X'"
I want to convert it to
eng="where session in ('001122') and indicator in ('X')"
I have tried like below using sed in bash
eng=$(echo $abc | sed -r "s/=\s+('[^']+')/in (\1)/g")
I am still get the input itself. What am I doing wrong.
You can use unadorned sed with escaped to escape the capture group parentheses (\( and \)), as well as one-or-more quantifiers (\+):
$ eng=$(echo "$abc" | sed "s/=\s\+'\([^']\+\)'/in ('\1')/g"
$ echo "$eng"
where session in ('001122') and indicator in ('X')
It is also probably a good idea to quote your expansion of abc, since it has spaces in it, but not strictly necessary in this context.
Your original code may not have worked because -r is a GNU extension. The synonym -E used to be as well, but is now part of the POSIX standard, and should therefore be relatively portable. The following version should therefore have no problems either:
$ eng=$(echo "$abc" | sed -E "s/=\s+'([^']+)'/in ('\1')/g"

why can't match the content between # and end of line in sed?

$ echo "haha#nihao" | sed "s/#.+$/end/"
haha#nihao
I want to match contents between character # and the end of line.why can't i get it?
:%!sed "s/#.\+$/end/"
E194:No alternate file name to substitute for '#'
problem 1:
why i can't use it in sed of vim?
problem 2:
how to see the EORROR 194 ?
problem 1: why i can't use it in sed of vim?
Because by default sed uses BRE, basic regular expressions:
/.+/ this matches any character followed by a "+"
/.\+/ this matches one or more occurrences of any character
You can tell sed to use extended regular expressions with the -r flag in GNU implementations and -E flag with BSD implementations:
$ echo "haha#nihao" | sed -r "s/#.+$/end/"
hahaend
problem 2: how to see the EORROR 194 ?
You get this error because # has a special meaning in vim when you run commands with !: # marks on the command line are replaced with the alternate file. It should work if you escape the #:
%!sed "s/\#.\+$/end/"
You can read about this error with the :help E194 command, and about alternative file with :help alternate-file.
use sed -r
echo "haha#nihao" | sed -r "s/#.+$/end/"
hahaend
from man sed
-r, --regexp-extended
use extended regular expressions in the script.

sed and special char

im trying the following sed command, but i have no luck with special chars:
echo "x#asdf" | sed "s/\([^-]\)#/\1\n/g"
x
asdf
but if i use some special char in test.txt
echo "ä#asdf" | sed "s/\([^-]\)#/\1\n/g"
ä#asdf
why ?
this works:
echo "ü#asdf" | sed "s/ü/-/g"
-#asdf
but this doesnt:
echo "ü#asdf" | sed "s/[ü]/-/g"
ü#asdf
I'm not sure about this, because your sed commands work ok for me (gnu sed 4.1.5), but try invoking sed this way:
$ LANG=de_DE.UTF-8 sed ...
See this post for more information: Why does sed fail with International characters and how to fix?.
If this doesn't work, it may help to upgrade to gnu sed 4.2, if you can. The NEWS file says "multibyte processing fixed" for 4.2 but does not go into further detail.

Replacing the last word of a path using sed

I have the following: param="/var/tmp/test"
I need to replace the word test with another word such as new_test
need a smart way to replace the last word after "/" with sed
echo 'param="/var/tmp/test"' | sed 's/\/[^\/]*"/\/REPLACEMENT"/'
param="/var/tmp/REPLACEMENT"
echo '/var/tmp/test' | sed 's/\/[^\/]*$/\/REPLACEMENT/'
/var/tmp/REPLACEMENT
Extracting bits and pieces with sed is a bit messy (as Jim Lewis says, use basename and dirname if you can) but at least you don't need a plethora of backslashes to do it if you are going the sed route since you can use the fact that the delimiter character is selectable (I like to use ! when / is too awkward, but it's arbitrary):
$ echo 'param="/var/tmp/test"' | sed ' s!/[^/"]*"!/new_test"! '
param="/var/tmp/new_test"
We can also extract just the part that was substituted, though this is easier with two substitutions in the sed control script:
$ echo 'param="/var/tmp/test"' | sed ' s!.*/!! ; s/"$// '
test
You don't need sed for this...basename and dirname are a better choice for assembling or disassembling pathnames. All those escape characters give me a headache....
param="/var/tmp/test"
param_repl=`dirname $param`/newtest
It's not clear whether param is part of the string that you need processed or it's the variable that holds the string. Assuming the latter, you can do this using only Bash (you don't say which shell you're using):
shopt -s extglob
param="/var/tmp/test"
param="${param/%\/*([^\/])//new_test}"
If param= is part of the string:
shopt -s extglob
string='param="/var/tmp/test"'
string="${string/%\/*([^\/])\"//new}"
This might work for you:
echo 'param="/var/tmp/test"' | sed -r 's#(/(([^/]*/)*))[^"]*#\1newtest#'
param="/var/tmp/newtest"

How do I push `sed` matches to the shell call in the replacement pattern?

I need to replace several URLs in a text file with some content dependent on the URL itself. Let's say for simplicity it's the first line of the document at the URL.
What I'm trying is this:
sed "s/^URL=\(.*\)/TITLE=$(curl -s \1 | head -n 1)/" file.txt
This doesn't work, since \1 is not set. However, the shell is getting called. Can I somehow push the sed match variables to that subprocess?
The accept answer is just plain wrong. Proof:
Make an executable script foo.sh:
#! /bin/bash
echo $* 1>&2
Now run it:
$ echo foo | sed -e "s/\\(foo\\)/$(./foo.sh \\1)/"
\1
$
The $(...) is expanded before sed is run.
So you are trying to call an external command from inside the replacement pattern of a sed substitution. I dont' think it can be done, the $... inside a pattern just allows you to use an already existent (constant) shell variable.
I'd go with Perl, see the /e option in the search-replace operator (s/.../.../e).
UPDATE: I was wrong, sed plays nicely with the shell, and it allows you do to that. But, then, the backlash in \1 should be escaped. Try instead:
sed "s/^URL=\(.*\)/TITLE=$(curl -s \\1 | head -n 1)/" file.txt
Try this:
sed "s/^URL=\(.*\)/\1/" file.txt | while read url; do sed "s#URL=\($url\)#TITLE=$(curl -s $url | head -n 1)#" file.txt; done
If there are duplicate URLs in the original file, then there will be n^2 of them in the output. The # as a delimiter depends on the URLs not including that character.
Late reply, but making sure people don't get thrown off by the answers here -- this can be done in gnu sed using the e command. The following, for example, decrements a number at the beginning of a line:
echo "444 foo" | sed "s/\([0-9]*\)\(.*\)/expr \1 - 1 | tr -d '\n'; echo \"\2\";/e"
will produce:
443 foo