How to express variable in sed? [duplicate] - regex

This question already has answers here:
Is it possible to escape regex metacharacters reliably with sed
(4 answers)
Closed 2 years ago.
$ VAR="this is working well"
$ sed -i "s/$/,$VAR/" my.txt
$ VAR="this/got/error"
$ sed -i "s/$/,$VAR/" my.txt
sed: -e expression #1, char 12: unknown option to `s
I have to put various kind of strings to $VAR.
Sometimes $VAR is not working with sed. Bcoz of special character.
How can I solve this problem with sed or regular expression?
Thank u in advance.

sed does not have the concept of variables, and the variable you're using is being interpreted by the shell before sed even sees it. Because of this, if you want to use some sort of variable that can handle arbitrary text, you need to use a different tool which can do this.
For example, you could do this using Perl:
$ perl -i 's/$/,$ENV{VAR}/g' my.txt
or you could do it using awk and a temporary file:
$ awk '{ sub(/$/, "," ENVIRON["VAR"]); print }' my.txt > temp && mv temp my.txt
Note that using sed -i, regardless of whether it has this problem or not, is not portable. On macOS, you must use sed -i '', but that syntax does not work on Linux. The perl -i invocation is portable to all systems using Perl, as would be an equivalent technique using ruby -i.

Whilst sed tutorials typically use / as the search/replace delimiters, you can use many other symbols as delimiters. For example s/one/two/ could also be written as s|one|two or as s#one#two.
So - to solve your particular problem, the solution is simple - use a different delimiter.
$ cat file.txt
1
2
3
4
$ VAR="this is working well"
$ sed 's/$/,'"$VAR"'/' file.txt
1,this is working well
2,this is working well
3,this is working well
4,this is working well
$ VAR="this/got/error"
$ sed 's|$|,'"$VAR"'|' file
1,this/got/error
2,this/got/error
3,this/got/error
4,this/got/error
$

Related

Can I perform a 'non-global' grep and capture only the first match found for each line of input?

I understand that what I'm asking can be accomplished using awk or sed, I'm asking here how to do this using GREP.
Given the following input:
.bash_profile
.config/ranger/bookmarks
.oh-my-zsh/README.md
I want to use GREP to get:
.bash_profile
.config/
.oh-my-zsh/
Currently I'm trying
grep -Po '([^/]*[/]?){1}'
Which results in output:
.bash_profile
.config/
ranger/
bookmarks
.oh-my-zsh/
README.md
Is there some simple way to use GREP to only get the first matched string on each line?
I think you can grep non / letters like:
grep -Eo '^[^/]+'
On another SO site there is another similar question with solution.
You don't need grep for this at all.
cut -d / -f 1
The -o option says to print every substring which matches your pattern, instead of printing each matching line. Your current pattern matches every string which doesn't contain slashes (optionally including a trailing slash); but it's easy to switch to one which only matches this pattern at the beginning of a line.
grep -o '^[^/]*' file
Notice the addition of the ^ beginning of line anchor, and the omission of the -P option (which you were not really using anyway) as well as the silly beginner error {1}.
(I should add that plain grep doesn't support parentheses or repetitions; grep -E would support these constructs just fine, of you could switch to toe POSIX BRE variation which requires a backslash to use round or curly parentheses as metacharacters. You can probably ignore these details and just use grep -E everywhere unless you really need the features of grep -P, though also be aware that -P is not portable.)

Two seemingly identical sed commands, one works, the other doesn't. Can you tell me why? [duplicate]

This question already has answers here:
Difference between single and double quotes in Bash
(7 answers)
Closed 7 years ago.
There's something I'm having trouble understanding concerning sed behavior.
sed -n "/pattern/,$p" < input.inp > output.out
gives the following error
sed: -e expression n°1, caractère 10: `,' inattendue
(my system is in french).
sed -n '/pattern/,$p' < input.inp > output.out
Works fine
I've personnally used commands like
sed -n "/begin/,/end/p" < input.inp > output.out
with both single or double quotes, and they work just fine.
In case it's useful, I have sed version: sed (GNU sed) 4.2.2
In double quotes, the shell, not sed, will evaluate $p. Since you probably haven't set a variable named p, sed will only see /pattern/,. To prevent this from happening, you'd need to escape the $ to the shell, by writing \$ instead:
sed -n "/pattern/,\$p" < input.inp > output.out
(You can imagine that using single quotes is a lot easier on the eyes and brain, unless you need shell variables in your expression.)

Linux - Only find a pattern within a line, not the whole line

I want to use a regex to find a pattern in a file. That pattern may be in the middle of a line, but I don't want the whole line. I tried grep -a pattern file but this returns the entire line that contains the regex. The following is an example of what I'm trying to do. Does anyone know a way to do this?
Example:
Input: AAAAAAAAAAAAAXxXxXxXxBananasyYyYyYyYBBBBBBBCCCCCC
Regex: Xx.*yY
Ouput: XxXxXxXxBananasyYyYyYyY
you were close, you need the -o flag
grep -o 'Xx.*yY' <<<AAAAAAAAAAAAAXxXxXxXxBananasyYyYyYyYBBBBBBBCCCCCC
XxXxXxXxBananasyYyYyYyY
Use the -o option to print just the part of the line that matches the regexp
grep -o pattern file
In addition to grep -o (the simplest way), there are a couple of other options:
In bash, without relying on any particular implementation of grep:
$ regex='Xx.*yY'
$ [[ AAAAAAAAAAAAAXxXxXxXxBananasyYyYyYyYBBBBBBBCCCCCC =~ $regex ]]
$ echo ${BASH_REMATCH[0]}
XxXxXxXxBananasyYyYyYyY
Using expr, which is a little unwieldy (in part because the regular expression is implicitly anchored to the beginning of the string), but is defined by the POSIX standard so it should work on any POSIX platform, regardless of the shell used.
$ expr AAAAAAAAAAAAAXxXxXxXxBananasyYyYyYyYBBBBBBBCCCCCC : '[^X]*\(Xx.*yY\)'
XxXxXxXxBananasyYyYyYyY

RegEx to get the pattern for a output string in shell script

I run the command grep to get certain output and store it into a variable. The output of grep command is:
5.3.1-6.2011171513.ASMOS6
but I need to only parse out 5.3.1-6 and store that version in a variable. How can I do that?
What about this?
TEXT=5.3.1-6.2011171513.ASMOS6
RES=$(echo $TEXT | cut -d. -f-3)
We cut the string on . and then get the first 3 pieces.
With awk
RES=$(echo $TEXT | awk -F. 'OFS=FS {print $1,$2,$3}')
OFS=FS meaning we get the delimiter to print that was defined with -F.
As you tag says linux, I'll assume that you have a modern grep that supports the -o option.
You can do
var=$(grep -o 'regex' file)
To capture just the regex to a variable.
Unfortunately, I don't understand the problem you're having getting just 5.3.1-6, you have to edit your question to show us the regex youare currently using.
IHTH

Print RegEx matches using SED in bash

I have an XML file, the file is made up of one line.
What I am trying to do is extract the "finalNumber" attribute value from the file via Putty. Rather than having to download a copy and search using notepad++.
I've built up a regular expression that I've tested on an On-line Tool, and tried using it within a sed command to duplicate grep functionality. The command runs but doesn't return anything.
RegEx:
(?<=finalNumber=")(.*?)(?=")
sed Command (returns nothing, expected 28, see file extract):
sed -n '/(?<=finalNumber=")(.*?)(?=")/p' file.xml
File Extract:
...argo:finalizedDate="2012-02-09T00:00:00.000Z" argo:finalNumber="28" argo:revenueMonth=""...
I feel like I am close (i could be wrong), am I on the right lines or is there better way to achieve the output?
Nothing wrong with good old grep here.
grep -E -o 'finalNumber="[0-9]+"' file.xml | grep -E -o '[0-9]+'
Use -E for extended regular expressions, and -o to print only the matching part.
Though you already select an answer, here is a way you can do in pure sed:
sed -n 's/^.*finalNumber="\([[:digit:]]\+\)".*$/\1/p' <test
Output:
28
This replaces the entire line by the match number and print (because p will print the entire line so you have to replace the entire line)
This might work for you (GNU sed):
sed -r 's/.*finalNumber="([^"]*)".*/\1/' file
sed does not support look-ahead assertions. Perl does, though:
perl -ne 'print $1 if /(?<=finalNumber=")(.*?)(?=")/'
As I understand, there is no need to use look-aheads here.
Try this one
sed -n '/finalNumber="[[:digit:]]\+"/p'