How do I replace every occurance using AWK statement - linux

How can I adjust the following code to replace every occurrence of the value set for the element, ThreadGroup.num_threads.
Here is the code I'm trying to make work.
awk ' BEGIN { FS = "[<|>]" }
{
if ($2 == "stringProp name=\"ThreadGroup.num_threads\"") {
$newValue
}
print
}
' Test1.jmx
Here is the XML snippet I'm parsing.
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
<stringProp name="ThreadGroup.num_threads">3</stringProp>
</ThreadGroup>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group2" enabled="true">
<stringProp name="ThreadGroup.num_threads">3</stringProp>
</ThreadGroup>
newValue=999999

In your code, the variable newValue is never defined. Moreover, you do not need $ in front of your own variables.
Here is my suggestion:
awk '$0 ~ /stringProp name="ThreadGroup.num_threads"/
{sub(/<stringProp name="ThreadGroup.num_threads">[0-9]+/,
"<stringProp name=\"ThreadGroup.num_threads\">999999",
$0)}
{}1' inputFile
1st line: I check whether the current line contains the text stringProp name="ThreadGroup.num_threads"
2nd-4th line: If yes, I substitute the string <stringProp name="ThreadGroup.num_threads"> if it is followed by one or more numbers by the same string followed by 999999.
5th line: Finally, I output each line.
Of course you can define a variable:
awk 'BEGIN{newValue=999999}
$0 ~ /stringProp name="ThreadGroup.num_threads"/
{sub(/<stringProp name="ThreadGroup.num_threads">[0-9]+/,
"<stringProp name=\"ThreadGroup.num_threads\">"newValue,
$0)}
{}1' inputFile
The output is:
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
<stringProp name="ThreadGroup.num_threads">999999</stringProp>
</ThreadGroup>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group2" enabled="true">
<stringProp name="ThreadGroup.num_threads">999999</stringProp>
</ThreadGroup>

Perhaps this is easier with sed
$ sed -r 's/("ThreadGroup.num_threads">)([0-9]+)</\19999</g'

Related

How to I remove the white space between overridable="true" and default using shell script?

<Property name="wt.99999" overridable="true"
default="ext.listner.services.ListnerService/ext.listner.services.ListnerService"/>
I want to remove the space using shell script.
I write this code.
filename2=CECWT.xconf
c=wt.99999
c1=ext.listner.services.ListnerService
grep -w "$c\|$c1" $filename2 > output.txt
cat output.txt | trim
I want output :
<Property name="wt.99999" overridable="true" default="ext.listner.services.ListnerService/ext.listner.services.ListnerService"/>
You could use this GNU sed command:
sed '/overridable=/N; N; s/\n\s*/ /g' your_file
It finds any line with containing the string 'overridable=' and then reads in
the next 2 lines (N; N) since in your example there is a blank line before
the one you want. Then removes the newline characters and any trailing space
\n\s*, replacing them with spaces, resulting in a single joined line. (Note
this command will only work for the case of a single blank line between the two
lines you want joined!)
If you want to do the replacement in-place (i.e. overwrite the contents of the
your_file, you can add the -i flag:
sed -i '/overridable=.*/N; N; s/\n\s*/ /g' your_file
This page https://www.grymoire.com/Unix/Sed.html explains sed very well if you
want to learn it.
Trying the command
When I test the command on a file called 'your_file' which has the contents:
<Property name="wt.99999" overridable="true"
default="ext.listner.services.ListnerService/ext.listner.services.ListnerService"/>
I get:
<Property name="wt.99999" overridable="true" default="ext.listner.services.ListnerService/ext.listner.services.ListnerService"/>
grep alone does not seem like a very good tool for this. If your input is proper XML, using a real XML tool to reformat it is probably the way to go. But if you just need to clean something up quickly, try this simple Awk script:
awk '/<Property name="wt.99999"/ { printf "%s", $0; isprop=1; next }
/^[ \t]*$/ && isprop { next; }
{ isprop=0 } 1' CECWT.xconf >output.txt
The 1 at the end prints the input line with newline and all. We special-case the line which matches the first regex to print that without the newline. We then add a state variable to also skip any lines with only whitespace on them (or nothing at all) until we find a line which doesn't match either regex.
This will still leave whitespace from the end of the property line and whitespace from the beginning of the following line; trimming that complicates the script slightly, but not by much.
awk '/<Property name="wt.99999"/ { printf "%s", $0; isprop=1; next }
/^[ \t]*$/ && isprop { next; }
isprop { sub(/^[ \t]*/, " "); isprop=0 } 1' CECWT.xconf >output.txt

using sed to extract certain strings from config file

I am trying to export certain strings from below output, however i have no experience with sed/awk and i need some advise how can i proceed with that.
Input:
name Cleartext-Password := "password", Service-Type := Framed-User
Framed-IP-Address := 127.0.0.1,
MS-Primary-DNS-Server := 8.8.8.8,
Fall-Through = Yes,
Mikrotik-Rate-Limit = 20M/30M
The output should be:
name;password;127.0.0.1;20M;30M;
I am not sure if this is correct way to do that, but i have tried to remove everything between my required string, for example:
sed 's/ Cleartext-Password := "/;/'
However i think this is dirty way and not the clever one.
Could you please let me know what i need to look for in order to create working sed/awk solution for this?
Could you please try following based on your shown samples. Written and tested it in site
https://ideone.com/eWXv3w
Since OP's Input_file has control M characters so added gsub(/\r/,"") in code here.
awk '
BEGIN{ OFS=";" }
{ gsub(/\r/,"") }
match($0,/Cleartext-Password[^,]*/){
val=substr($0,RSTART,RLENGTH)
gsub(/Cleartext-Password[^"]*|"/,"",val)
val=$1 OFS val
next
}
/Framed-IP-Address/{
sub(/,$/,"")
val=val OFS $NF
next
}
/Mikrotik-Rate-Limit/{
print val, $NF
val=""
}' Input_file
Explanation: In BEGIN section of program setting OFS to semi colon as per question. Then using match function of awk to match regex from string Cleartext...Cleartext-Password[^,]* till first comma comes. If regex matches perfectly then capturing that sub-string in variable val here. Now using gsub to globally substitute everything from Cleartext-Password and all un-necessary stuff there as per required output.
Then checking if line contains Framed-IP-Address if it's found then send substituting , from last of line and adding that line last field to variable val here.
Now checking condition if a line contains Mikrotik-Rate-Limit then simply printing value of val and last field here, nullifying val here too.
There are a number of ways to approach this with awk, the key is to match part of the record with the regular expression to identify the record you are operating on and then isolate the wanted test and output in the desired format.
One approach would be:
awk '
/Cleartext-Password/ { printf "%s;%s;", $1, substr($4,2,length($4)-3) }
/Framed-IP-Address/ { printf "%s;", substr($NF,1,length($NF)-1) }
/Mikrotik-Rate-Limit/{ sub(/\//,";",$NF); printf "%s;\n", $NF }
' config
Example Use/Output
With your sample input in the file named config, you would receive:
name;password;127.0.0.1;20M;30M;
Look things over and let me know if I misunderstood anywhere.
This might work for you (GNU sed):
sed -nE -e '/Cleartext-Password/{s/ .*:=\s"(.*)",.*/;\1/;h}' \
-e '/Framed-IP-Address/{s/.*:= (.*),/\1/;H}' \
-e '/Mikrotik-Rate-Limit/{s#.*= (.*)/(.*)#\1;\2#;H;g;y/\n/;/;p}' file
Turn off implicit printing by invoking the -n option.
Reduce back slashes by invoking the -E option.
Stash the fields of the record in the hold space and when all fields have been collected, copy the hold space to the pattern space, replace newlines by the field separators and print the result.
You may prefer:
sed -nE '/Cleartext-Password/{s/ .*:=\s"(.*)",.*/;\1/;h};
/Framed-IP-Address/{s/.*:= (.*),/\1/;H};
/Mikrotik-Rate-Limit/{s#.*= (.*)/(.*)#\1;\2#;H;g;y/\n/;/;p}' file

bash extract segments of a string and store in variables

I want to convert the output from cppclean into cppcheck-like xml sections, such that:
./bit_limits.cpp:25: static data 'bit_limits::max_name_length'
becomes:
<error id="static data" msg="bit_limits::max_name_length">
<location file="./bit_limits.cpp" line="25"/>
</error>
I started with some awk:
test code:
echo "./bit_limits.cpp:25: static data 'bit_limits::max_name_length'" > test
cat test.out | awk -F ":" '{print "<error id=\""$3"\""}
{print "msg=\""}{for(i=4;i<=NF;++i)print ":"$i}{print "\">"}
{print "<location file=\""$1"\" line=\""$2"\"/>"}
{print "</error>"}'
Note: to run this you need to put the cat command back into one line - I printed it over multi-lines for ease of reading.
Explanation:
I am using awk and delimiting by colon ":" - which splits the line into useful chunks which I try to construct into the XML:
{print "<error id=\""$3"\""} - Extract the error ID part
{print "msg=\""}{for(i=4;i<=NF;++i)print ":"$i}{print "\">"} - extract the message (replacing the missing colons, this is all the remaining sections
{print "<location file=\""$1"\" line=\""$2"\"/>"} - extract the file and line, this part is easy since the colons line up nicely
{print "</error>"} - finally print the end tag
This is close, but not quite right, it produces:
<error id=" static data 'bit_limits"
msg="
:
:max_name_length'
">
<location file="./bit_limits.cpp" line="25"/>
</error>
The id field should just be "static data" and the msg field should be "'bit_limits::max_name_length'", but other then that it is ok (I don't mind it being split of multi-lines at the moment - though I would prefer that awk did not print a new line each time.
Update
As #charlesduffy pointed out - for context - I want to do this in bash because I want to embed this code into a makefile (or just a normal bash script) for maximum portability (i.e. no need for python or other tools).
With bash and a regex:
x="./bit_limits.cpp:25: static data 'bit_limits::max_name_length'"
[[ $x =~ (.+):([0-9]+):\ (.+)\ \'(.+)\' ]]
declare -p BASH_REMATCH
Output:
declare -ar BASH_REMATCH='([0]="./bit_limits.cpp:25: static data '\''bit_limits::max_name_length'\''" [1]="./bit_limits.cpp" [2]="25" [3]="static data" [4]="bit_limits::max_name_length")'
The elements 1 to 4 in array BASH_REMATCH contain the searched strings.
From man bash:
BASH_REMATCH: An array variable whose members are assigned by the =~ binary operator to the [[ conditional command. The element with index 0 is the portion of the string matching the entire regular expression. The element with index n is the portion of the string matching the nth parenthesized subexpression. This variable is read-only.
Probably more complex than it needs to be:
awk '{
split($1, file_line, ":")
field = 2
while(substr($field, 1, 1) != "'\''") {
id = id " " $field
++field
}
id = substr(id, 2)
while(field <= NF) {
msg = msg " " $field
++field
}
msg = substr(msg, 3, length(msg) - 1)
printf("<error id=\"%s\" msg=\"%s\">\n", id, msg)
printf(" <location file=\"%s\" line=\"%s\">\n", file_line[1], file_line[2])
print "</error>"
}' test.out

Find a pattern and replace

This is the input to my file.
Number : 123
PID : IIT/123/Dakota
The expected output is :
Number : 111
PID : IIT/111/Dakota
I want to replace 123 to 111. To solve this I have tried following:
awk '/Number/{$NF=111} 1' log.txt
awk -F '[/]' '/PID/{$2="123"} 1' log.txt
Use sed for something this simple ?
Print the change to the screen (test with this) :
sed -e 's:123:111:g' f2.txt
Update the file (with this) :
sed -i 's:123:111:g' f2.txt
Example:
$ sed -i 's:123:111:g' f2.txt
$ cat f2.txt
Number : 111
PID : IIT/111/Dakota
EDIT2: Or you want to substitute each line's 123 with 111 without checking any condition which you tried in your awk then simply do:
awk '{sub(/123/,"111")} 1' Input_file
Change sub to gsub in case of many occurrences of 123 in a single line too.
Explanation of above code:
awk -v new_value="111" ' ##Creating an awk variable named new_value where OP could keep its new value which OP needs to be there in line.
/^Number/ { $NF=new_value } ##Checking if a line starts from Number string and then setting last field value to new_value variable here.
/^PID/ { num=split($NF,array,"/"); ##Checking if a line starts from PID then creating an array named array whose delimiter it / from last field value
array[2]=new_value; ##Setting second item of array to variable new_value here.
for(i=1;i<=num;i++){ val=val?val "/" array[i]:array[i] }; ##Starting a loop from 1 to till length of array and creating variable val to re-create last field of current line.
$NF=val; ##Setting last field value to variable val here.
val="" ##Nullifying variable val here.
}
1' Input_file ##Mentioning 1 to print the line and mentioning Input_file name here too.
EDIT: In case you need to / in your output too then use following awk.
awk -v new_value="111" '
/^Number/ { $NF=new_value }
/^PID/ { num=split($NF,array,"/");
array[2]=new_value;
for(i=1;i<=num;i++){ val=val?val "/" array[i]:array[i] };
$NF=val;
val=""
}
1' Input_file
Following awk may help you here.(Seems after I have applied code tags to your samples your sample input is changed a bit so editing my code accordingly now)
awk -F"[ /]" -v new_value="111" '/^Number/{$NF=new_value} /^PID/{$(NF-1)=new_value}1' Input_file
In case you want to save changes into Input_file itself append > temp_file &7 mv temp_file Input_file in above code then.
Explanation:
awk -F"[ /]" -v new_value="111" ' ##Setting field separator as space and / to each line and creating awk variable new_value which OP wants to have new value.
/^Number/{ $NF=new_value } ##Checking condition if a line is starting with string Number then change its last field to new_value value.
/^PID/ { $(NF-1)=new_value } ##Checking condition if a line starts from string PID then setting second last field to variable new_value.
1 ##awk works on method of condition then action, so putting 1 making condition TRUE here and not mentioning any action so by default print of current line will happen.
' Input_file ##Mentioning Input_file name here.

find a string in a string using awk

here is column 6 in a file:
ttttttttttt
tttttttttt
ttttttttt
tttttttattt
tttttttttt
ttttttttttt
how can I use awk to print out lines that include "a"
If you only want to search the sixth column, use:
awk '$6 ~ /a/' file
If you want the whole line, any of these should work:
awk /a/ file
grep a file
sed '/^[^a]*$/d' file
If you wish to print only those lines in which 6th column contains a then this would work -
awk '$6~/a/' file
if it is an exact match (which yours is not) you're looking for:
$6 == "a"
http://www.pement.org/awk/awk1line.txt
is an excellent resource
awk can also tell you where the pattern is in the column:
awk '{++line_num}{ if ( match($6,"a")) { print "found a at position",RSTART, " line " ,line_num} }' file
though this example will only show the first "a" in column 6; a for loop would be needed to show all instances (I think)
You could try
gawk '{ if ( $1 ~ /a/ ) { print $1 } }' filename

Resources