Replacing a string in a file using bash shell scri

2019-07-17 06:21发布

I want to find a string in a file, do some operation and put back the string in the file. Given below is the example on what I need:

$ cat sample.txt
TimeStamp-> 123456 Name-> ABC Mail-> abc@123.com
TimeStamp-> 23456 Name-> XYZ Age-> 25

Let me modify my question. I want to read that string/number after TimeStamp->, modify the same based on the requirement and put it back to get in the same file or create a new file. Let's say the operation is multiply by -1.

Expected output is:

TimeStamp-> -123456 Name-> ABC Mail-> abc@123.com
TimeStamp-> -23456 Name-> XYZ Age-> 25

4条回答
Evening l夕情丶
2楼-- · 2019-07-17 06:54

Here a pure bash solution:

while read -ra line; do # read each line in the array "line"
    ((line[1]*=-1))     # multiply the second element (the number) by -1.
    echo "${line[*]}"   # echo the modified line into newfile.txt
done < sample.txt > newfile.txt

Explanation

The while loop just read each line into an array:

read options:

-r
If this option is given, backslash does not act as an escape character. The backslash is considered to be part of the line. In particular, a backslash-newline pair may not be used as a line continuation.

-a aname
The words are assigned to sequential indices of the array variable aname, starting at 0. All elements are removed from aname before the assignment. Other name arguments are ignored.

and then uses Shell Arithmetic (*=) to multiply the number (an arithmetic expression) and echo'es the modified line to newfile.txt.

查看更多
手持菜刀,她持情操
3楼-- · 2019-07-17 07:03

Thanks for all the help. It worked with while loop and sed -i. Code is as given below:

awk '{print $2}' sample.txt |
while read line
do
    timestamp=$(echo $line |awk '{print $1}')
    converted=$(echo $line |awk '{print $1*-1}')
    sed -i "s/TimeStamp-> $timestamp/TimeStamp-> $converted/" sample.txt
done

Before:

cat sample.txt
TimeStamp-> 123456 Name-> ABC Mail-> abc@123.com
TimeStamp-> 12345 Name-> XYZ Age-> 25

After:

cat sample.txt
TimeStamp-> -123456 Name-> ABC Mail-> abc@123.com
TimeStamp-> -12345 Name-> XYZ Age-> 25
查看更多
Ridiculous、
4楼-- · 2019-07-17 07:07

Your mental model of the problem seems rather inadequate. There is a number of ways to convert a file into another file, so a traditional approach would be to produce a new file by various means, then move it on top of the original file. But for simplicity, you could use a tool which explicitly supports in-place editing, such as Perl.

perl -pi~ -e 's/(TimeStamp->\s*)(\d+)/ sprintf("%s%s", $1, -1*$2) /gx' file

This is a regular expression substitution s/from/to/ with the /x option to allow the replacement to be produced by another Perl expression, rather than just a string. It would not be hard to write a simple date conversion call instead of the sprintf placeholder. The regex captures the static string TimeStamp-> and any trailing whitespace into $1, and the number into $2.

A somewhat more "shellish" solution would be to extract the number, run a tool or process on it, and replace the string separately. Assuming you have a sed which supports the i option, and a tool called ssboetod to calculate a replacement value, perhaps something like

timestamp=$(sed -n '/.*TimeStamp-> */!d;s///;s/ .*//' file)
converted=$(ssboetod "$timestamp")
sed -i "s/TimeStamp-> *$timestamp/TimeStamp-> $converted/" file

With two process substitutions, this isn't particularly elegant, though. I added this as an illustration of a typical approach more than as an actual answer.

Finally, if the input file format is under your control, I would recommend a redesign. This looks vaguely like logging data, so a semi-standard log file format would perhaps make more sense. The tagged fields, on the other hand, suggest thinking about switching to JSON for this data, although that would not simplify the handling of this particular problem.

查看更多
啃猪蹄的小仙女
5楼-- · 2019-07-17 07:10

If there is a constant number of columns in your file, and you know that the number you wish to manipulate via arithmetic is located in column 2, as it is in your sample, then you may use awk:

awk '{print $1,$2*-1,$3,$4,$5,$6}' file > newFile

Notice I multiplied column 2, $2, by -1.

newFile should contain:

TimeStamp-> -123456 Name-> ABC Mail-> abc@123.com
TimeStamp-> -23456 Name-> XYZ Age-> 25
查看更多
登录 后发表回答