使用 bash shell 脚本替换文件中的字符串

Replacing a string in a file using bash shell script

我想在一个文件中找到一个字符串,做一些操作然后把这个字符串放回文件中。以下是我需要的示例:

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

让我修改一下我的问题。我想在TimeStamp->之后阅读string/number,根据需要修改相同的内容并将其放回同一文件或创建一个新文件。假设操作乘以 -1。

预期输出为:

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

您对问题的心智模型似乎很不充分。有多种方法可以将一个文件转换成另一个文件,因此传统的方法是通过各种方式生成一个新文件,然后将其移动到原始文件之上。但为简单起见,您可以使用明确支持就地编辑的工具,例如 Perl。

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

这是一个带有 /x 选项的正则表达式替换 s/from/to/,允许替换由另一个 Perl 表达式生成,而不仅仅是一个字符串。编写一个简单的日期转换调用而不是 sprintf 占位符并不难。正则表达式将静态字符串 TimeStamp-> 和任何尾随空格捕获到 </code>,并将数字捕获到 <code>.

一种更 "shellish" 的解决方案是提取数字,运行 一个工具或过程,然后单独替换字符串。假设您有一个支持 i 选项的 sed,以及一个名为 ssboetod 的工具来计算替换值,可能类似于

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

虽然有两个进程替换,但这并不是特别优雅。我将其添加为典型方法的说明,而不是实际答案。

最后,如果输入文件格式在您的控制之下,我建议重新设计。这看起来有点像日志数据,因此半标准的日志文件格式可能更有意义。另一方面,标记的字段建议考虑切换到此数据的 JSON,尽管这不会简化此特定问题的处理。

如果您的文件中的列数是固定的,并且您知道您希望通过算术运算的数字位于第 2 列,就像在您的示例中一样,那么您可以使用 awk:

awk '{print ,*-1,,,,}' file > newFile

注意我将第 2 列 </code> 乘以 <code>-1

newFile 应包含:

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

这里是一个纯粹的 bash 解决方案:

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

说明

while 循环将每一行 read 循环成 array:

read 选项:

-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.

然后使用Shell Arithmetic*=)乘以数字(算术表达式)和echo是修改后的行至 newfile.txt.

感谢大家的帮助。它适用于 while 循环和 sed -i。代码如下:

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

之前:

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

之后:

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