2

I need some solution to replace some string. I Have a "file" with this on the content:

23674, ICMP ping, OK, 1, 2016-08-25 17:11:02
23686, Ping, OK, 1, 2016-08-25 16:05:04
23689, SSH Service, OK, 1, 2016-08-25 16:05:49
23693, System Free Space, OK, 97.9560, 2016-08-25 16:06:49
23713, System Free Space, OK, 88.0078, 2016-09-20 18:02:22
23745, C:\ Free, OK, 63.2227, 2016-09-21 10:57:03

I used this code to take "Free" value on it like this:

 grep Free file.txt |grep OK | cut -d K -f 2 |cut -d , -f 2 |cut -d . -f 1

Then i got this result:

97
88
63

I need to insert "%" into the result using this code:

 grep Free rs.txt |grep OK | cut -d K -f 2 |cut -d , -f 2 |cut -d . -f 1 |sed 's/$/%/g'

The result like this:

97%
88%
63%

My question is, how to replace the value on the file for example "97.9560" with new result "97%" etc.
Kindly give me an advice. Thanks

2
  • I presume that rounding the floating value up or down is not important? Commented Sep 21, 2016 at 4:41
  • @l'L'l yes i rounding the float not important for me. Commented Sep 21, 2016 at 5:28

3 Answers 3

2

To replace the value in the file:

sed -E -i.bak 's/(Free.*OK,[^.]*)[.][^,]*/\1%/' file.txt

Example:

$ sed -E -i.bak 's/(Free.*OK,[^.]*)[.][^,]*/\1%/' file.txt
$ cat file.txt
23674, ICMP ping, OK, 1, 2016-08-25 17:11:02
23686, Ping, OK, 1, 2016-08-25 16:05:04
23689, SSH Service, OK, 1, 2016-08-25 16:05:49
23693, System Free Space, OK, 97%, 2016-08-25 16:06:49
23713, System Free Space, OK, 88%, 2016-09-20 18:02:22
23745, C:\ Free, OK, 63%, 2016-09-21 10:57:03

How it works

  • -E

    This tells sed to use extended regular expressions. This reduces the number of backslashes that we need.

  • -i.bak

    This tells to change the file in-place, leaving a back-up file.

  • s/(Free.*OK,[^.]*)[.][^,]*/\1%/

    This tells sed to make the substitution that you need. In this case, sed looks for text matching the regex (Free.*OK,[^.]*)[.][^,]*. This matches Free followed by OK, followed by anything except a period, followed by a period, followed by anything except a comma. The parentheses cause everything from Free to the last character before the period to be saved in group 1.

    The text that was matched is replace by \1% which means the text belonging to group 1, \1, followed by a percent sign, %.

Sign up to request clarification or add additional context in comments.

3 Comments

"This reduces the number of backslashes that we need." -- I do not see anything in your RE that requires extended RE; nor do I see anything that would require additional back-slashes if it is omitted. Also, I'd replace [.] with \.
@Sundeep -- Thank you for clarifying that. John1024 -- Good answer.
Thanks for the help and explanation @John1024 great answer
1

Here is awk version solution:

awk -v OFS=, -F, '/Free.*OK/ {split($4,a,"."); $4=a[1]"%"}1' infile
23674, ICMP ping, OK, 1, 2016-08-25 17:11:02
23686, Ping, OK, 1, 2016-08-25 16:05:04
23689, SSH Service, OK, 1, 2016-08-25 16:05:49
23693, System Free Space, OK, 97%, 2016-08-25 16:06:49
23713, System Free Space, OK, 88%, 2016-09-20 18:02:22
23745, C:\ Free, OK, 63%, 2016-09-21 10:57:03

Explanation :

this awk command will take actions on only those lines which contains Free followed by OK. As this file is a csv file, get the 4th field and split into two parts separated by . . print the part which is of interest after appending % sign to it.

sed is best suited for find and replace tasks as it support in-place replacement. However it can be achieved through awk using following way :

awk -v OFS=, -F, '/Free.*OK/ {split($4,a,"."); $4=a[1]"%"}1' infile > infile.tmp && mv infile.tmp infile

1 Comment

Well done; we wrote the same script at the same time. I slightly prefer awk -F, '/System Free Space/ {split($4, a, /[.]/); $4 = a[1] "%"} {print}' because OFS isn't needed, and IMO ending with 1 to indicate printing is obscure. @dongk: awk is your friend. Whenever you find yourself with a pipeline of cut & sed, it's a safe bet awk will be briefer and clearer.
0

Couple of perl solution

$ perl -pe 's/OK,\s*\d+\K\.\d+/%/ if /Free/' ip.txt
23674, ICMP ping, OK, 1, 2016-08-25 17:11:02
23686, Ping, OK, 1, 2016-08-25 16:05:04
23689, SSH Service, OK, 1, 2016-08-25 16:05:49
23693, System Free Space, OK, 97%, 2016-08-25 16:06:49
23713, System Free Space, OK, 88%, 2016-09-20 18:02:22
23745, C:\ Free, OK, 63%, 2016-09-21 10:57:03
  • OK,\s*\d+\K positive lookbehind, OK, followed by zero or more spaces and one or more digits
  • \.\d+ dot followed by one or more digits
  • replacement text is %, applied only when input line contains Free

Another way is to split input line on , and change 4th field

perl -F, -le '$F[3] =~ s/\.\d+/%/ if /Free/; print join",", @F' ip.txt 

If result is as expected, changes can be done inplace with

perl -i no backup

or

perl -i.bkp with backup

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.