replace one attribute on another with sed or awk - bash

<testcase classname='tc1' name='tc1' time='78.455094'/>
<testcase classname='tc2' name='tc2' time='78.549320'>
<failure type='fail-verdict'>
error message
</failure>
</testcase>
<testcase classname='tc3' name='tc_3' time='78.444719'/>
how to replace 3-rd attribute time in testcase tag to attribute status (status="pass" or "failure" based on testcase; for example: tc1,tc3 - pass, tc2- fail). I tried sed: sed -i 's/time=\'[0-9]+\.[0-9]+'/status="pass"/g' file.txt firstly without any logic..but it doesn't work.

You need the -E option (and -r for gnu sed) to use ERE (+ and more) or you should use [0-9][0-9]*
You cannot escape singlequotes inside single quotes, you need to do the following:
% echo 'hello'\'' world'
hello' world
Applied to your command:
sed -i 's/time='\''[0-9][0-9]*\.[0-9][0-9]*'\''/status="pass"/g' file.txt

Related

How to fix "unambiguous redirection" and "unknown option for the `s' command: for sed

I'm trying to undergo pdbqt-flexible files merge into one pdb using following script:
http://prosciens.com/prosciens/oldproscienssarl/files/flexrigidpdbqt2pdb_template.sh
Problematic fragment:
Let's merge the files
First we clean up the model PDB
grep ATOM ${FLEXPDBQT}_${MODEL}.pdb > ${FLEXPDBQT}_${MODEL}.pdb.tmp
Next we create a list of residues
cut -c 18-27 ${FLEXPDBQT}_${MODEL}.pdb.tmp > residuelistraw.tmp`
cat residuelistraw.tmp | uniq > residuelist.tmp
Then we split the model file into residues
while read r
do
rns= echo $r | sed 's/ //g'
egrep "[ \t]$r[ \t]" ${FLEXPDBQT}_${MODEL}.pdb.tmp > $rns.pdb.tmp
sed -i 's/'$FLEXPDBQT'_'$MODEL'.pdb.tmp://' $rns.pdb.tmp
Currently it fails at #3 step yielding following error:
/flexrigidpdbqt2pdb_template.sh: line 133: $ rns.pdb.tmp: ambiguous redirect
sed: -e expression # 1, character 9: unknown option for the `s' command
I tried fix the error using some sed substitution:
rns=`echo "${r/ /}"`
echo $rns
egrep "[ \t]$r[ \t]" ${FLEXPDBQT}_${MODEL}.pdb.tmp > $rns.pdb.tmp
sed -i 's/'$FLEXPDBQT'_'$MODEL'.pdb.tmp://' $rns.pdb.tmp
But so far nothing changed.
My sed version is 4.4
On the "ambiguous redirection" error
An "ambiguous redirection" error doesn't come from sed at all, it comes from your shell.
An "ambiguous redirection" error means your shell can't start the command you gave it at all, because it wasn't able to perform the redirections requested as part of that command's environment.
In that case, the variable rns is empty.
That's because rns= echo $r | sed 's/ //g' doesn't assign rns to be the output of sed at all. Instead, it assigns a transient environment variable named rns to be an empty string, only for the duration of execution of echo $r (the output of which is sent to sed, and from there to the script's stdout).
Instead, use:
rns=${r//[[:space:]]/}
...or, less efficiently:
rns=$(sed -e 's/ //g' <<<"$r")
To avoid the same error in cases where the variable isn't empty, be sure you quote!
That is, instead of running ... >$file, always run ... >"$file", to ensure that unwanted string-splitting or glob expansion can't make an otherwise-valid redirection unworkable. (This doesn't happen with all shell versions, but that means that failing to quote causes your code's behavior to be unpredictable unless you know which shell release it's going to be run with!).
On the "unknown option" error
If you use / as the sigil separating parts of your sed command, then you must not have any /s in the data being substituted. If you cannot guarantee this, use a different sigil instead of /; for example, s#/foo/bar#/baz/qux# works properly.
It looks like that the essential part to repair that script was changing rns as you proposed to:
rns=${r//[[:space:]]/}
and subsequent quoting of the output:
sed -i 's/'$FLEXPDBQT'_'$MODEL'.pdb.tmp://' "$rns.pdb.tmp"
However, further problems come out with next step, not previously shown:
sed '/'"HN ${r}"'/ r '${rns}'.pdb.tmp' ${RIGIDPDBQT}_${LIGNAME}_${MODEL}_apo.pdb > "${RIGIDPDBQT}_${LIGNAME}_${MODEL}_apo.pdb.tmp"
It yields no output (and no error), propably due to another problem with sed (which I really can't understand).
It is quite hard to give here a working example - a lot of preformatted txt files. Despite that, the problem about which I asked is solved, thank you!

Find two string in same line and then replace using sed

I am doing a find and replace using sed in a bash script. I want to search each file for words with files and no. If both the words are present in the same line then replace red with green else do nothing
sed -i -e '/files|no s/red/green' $file
But I am unable to do so. I am not receiving any error and the file doesn't get updated.
What am I doing wrong here or what is the correct way of achieving my result
/files|no/ means to match lines with either files or no, it doesn't require both words on the same line.
To match the words in either order, use /files.*no|no.*files/.
sed -i -r -e '/files.*no|no.*files/s/red/green/' "$file"
Notice that you need another / at the end of the pattern, before s, and the s operation requires / at the end of the replacement.
And you need the -r option to make sed use extended regexp; otherwise you have to use \| instead of just |.
This might work for you (GNU sed):
sed '/files/{/no/s/red/green/}' file
or:
sed '/files/!b;/no/s/red/green/' file
This method allows for easy extension e.g. foo, bar and baz:
sed '/foo/!b;/bar/!b;/baz/!b;s/red/green/' file
or fee, fie, foe and fix:
sed '/fee/!b;/fi/!b;/foe/!b;/fix/!b;s/bacon/cereal/' file
An awk verison
awk '/files/ && /no/ {sub(/red/,"green")} 1' file
/files/ && /no/ files and no have to be on the same line, in any order
sub(/red/,"green") replace red with green. Use gsub(/red/,"green") if there are multiple red
1 always true, do the default action, print the line.

Find and replace with sed and regex

I would like to use sed to replace version of assets files.
I have this on the file:
<script src="<?php echo assetsUrl ?>/ic-1548620973.js"></script>
and want update the timestamp with this command:
sed -i "s/(?<=ic-)(.*)(?=.js)/$timestamp.js/" src/views/partials/foot.view.php
The message error:
sed: 1: "src/views/partials/foot ...": unterminated substitute in regular expression
The sed on macOS isn't going to do things like it's counterpart on Linux, so you'll need to adjust it.
$ timestamp=$( date +%s )
$ sed -Ei '' 's#(ic-)(.*)(\.js)#\1'"$timestamp"'\3#g' src/views/partials/foot.view.php
You'll need to include the -E option because you are using capture groups, and the look-behinds are not necessary not to mention the fact that sed isn't the right tool for that. As for the in-place editing on macOS you have to include two single quotes '' after the -i option in order for it to save to the original file (in-place).
I changed the delimiters from / to # for readability. Essentially you have three capture groups, you'll include only the first and third one, while supplying the $timestamp variable in-between.
Output:
<script src="<?php echo assetsUrl ?>/ic-1548622266.js"></script>
Given that you have ruby installed:
ruby -i -ne 'puts $_.gsub(/(?<=ic-)\d+(?=\.js)/,Time.now.to_i.to_s)' src/views/partials/foot.view.php
I'm not sure, but seems ruby was preinstalled in MacOS, right?
Try this:
sed -i 's/(?<=ic-)(.*)(?=.js)/'"$timestamp.js"'/' src/views/partials/foot.view.php

SED change second occurence in all lines

The normal expression to change server1 to server1-bck is
sed -i 's/server1/server1-bck/g' file.out
so all server1 will be changed to server1-bck. What I need is to change the second occurence of the expression in every line.
For example,
before text:
rename files tsm_node1 //server1/document/users/ //server1/document/users/
desired after text:
rename files tsm_node1 //server1/document/users/ //server1-bck/document/users/
How can I do that?
echo "rename files tsm_node1 //server1/document/users/ //server1/document/users/" |\
sed 's/server1/server1-bck/2g'
sed's famous substitution works like this:
sed 's/regex/replacement/flags'
Flags could be a number, in your case 2 for advising sed to execute this command on 2nd occurrence and if you need more, therefore the g flag is. If you are sure, there are no more items to be substituted, you can leave and forget the g flag.
If you don't pipe and have a file, do this:
sed -i 's/server1/server1-bck/2g' file.out.
Additionally you can replace parts of your regex pattern with sed's & replacement if you want to substitute with that what you have found and will have:
sed -i 's/server1/&-bck/2g' file.out.

Bash variable in sed command

I need to add an header recursively to several file according to the name of the file.
So I have tried:
for i in *file
do
sed -i '1 i \A;B;C;D;E;F;G;H;${i%??}' a_${i} > header_a_${i}
done
the problem is that the variable reflecting the name of the file does not expand and in the header I have ${i%??} instead of part of the name file (%?? is to remove some ending characters).
Any help would be great.
Use double quotes:
sed '1 i\
A;B;C;D;E;F;G;H;'"${i%??}" a_${i} > header_a_${i}
It doesn't make any sense to use -i and to redirect the output, so I've omitted -i. Also, I've added an escaped newline after the insert command. Some sed do not require the newline, but many do. However, it seems odd to use sed for this. Instead, just do:
for i in *file; do
{ echo "A;B;C;D;E;F;G;H;${i%??}"; cat a_${i}; } > header_a_${i}
done

Resources