Bash 将2条awk或sed语句合并为一条并保存现有文件
我的目标是只修改以数据开头的行,其中只有一行。在这一行中,我将替换51-80个字符和97-126个字符。我宁愿使用sed的一行程序,因为这样我就可以使用Bash 将2条awk或sed语句合并为一条并保存现有文件,bash,date,awk,sed,Bash,Date,Awk,Sed,我的目标是只修改以数据开头的行,其中只有一行。在这一行中,我将替换51-80个字符和97-126个字符。我宁愿使用sed的一行程序,因为这样我就可以使用-I标志,然后它会根据需要保存文件 以下是我正在修改的文件中的行: data = '{\n"feature_name": "ALL",\n"start_date": "2020-06-07T08:34:00.000-06:00",\n"end_date": "2020-06-08T13:35:00.000-06:00",\n"product":
-I
标志,然后它会根据需要保存文件
以下是我正在修改的文件中的行:
data = '{\n"feature_name": "ALL",\n"start_date": "2020-06-07T08:34:00.000-06:00",\n"end_date": "2020-06-08T13:35:00.000-06:00",\n"product": "SAEP",\n"limit":1000\n}'
下面是我的两条awk语句,它们正在修改字符串的开始日期和结束日期部分。我包括了两个变量,我用来计算开始日期的当前时间减去15分钟前的时间,以及结束日期的当前时间:
ctime=`date +%Y-%m-%dT%H:%M:%S.%3N-00:00`
fifteen_min_ago=`date -d "15 mins ago" +%Y-%m-%dT%H:%M:%S.%3N-00:00`
awk '$1 ~ /^data/{printf "%s%*s%s\n",substr($0,1,m-1),n-m,"'$fifteen_min_ago'",substr($0,n)}' m=51 n=80 file
awk '$1 ~ /^data/{printf "%s%*s%s\n",substr($0,1,m-1),n-m,"'$ctime'",substr($0,n)}' m=97 n=126 file
这工作得很好,但我需要保存文件。如果我运行两个单独的awk命令,它一次只修改一个。因此,要么我将它们组合起来并使用awk保存,要么需要一个sed one-liner,然后我可以使用-I
谢谢。您可以内联多行awk脚本,也可以将这两条语句放在一个文件中。为每个“过程”使用不同的变量名
awk '
$1 ~ /^data/ {
$0 = sprintf("%s%*s%s\n",substr($0,1,m-1),n-m,"'$fifteen_min_ago'",substr($0,n))
$0 = sprintf("%s%*s%s\n",substr($0,1,m2-1),n2-m2,"'$ctime'",substr($0,n2))
}
{ print }
' m=51 n=80 m2=97 n2=126 file > file.new &&
mv file.new
注意,有其他(更简单的)方法来实现问题中实施的he替换。这与问题中描述的方法最为相似
使用SED,更换更容易:
ctime=$(date +%Y-%m-%dT%H:%M:%S.%3N-00:00)
fifteen_min_ago=$(date -d "15 mins ago" +%Y-%m-%dT%H:%M:%S.%3N-00:00)
sed -e 's/"start_date": "[^"]*"/"start_date": "'$ctime'"/' \
-e 's/"end_date": "[^"]*"/"end_date": "'$fifteen_min_ago'"/' < file > file.new && mv file.new file
ctime=$(日期+%Y-%m-%dT%H:%m:%S.%3N-00:00)
十五分钟以前=$(日期-d“十五分钟以前”+%Y-%m-%dT%H:%m:%S.%3N-00:00)
sed-e的/“开始日期”:“[^”]*”/“开始日期”:“$ctime”/”\
-e's/“结束日期”:“[^”]*”/“结束日期”:“$十五分钟前”/”file.new和&mv file.new文件
您可以内联多行awk脚本,也可以将这两条语句放在一个文件中。为每个“过程”使用不同的变量名
awk '
$1 ~ /^data/ {
$0 = sprintf("%s%*s%s\n",substr($0,1,m-1),n-m,"'$fifteen_min_ago'",substr($0,n))
$0 = sprintf("%s%*s%s\n",substr($0,1,m2-1),n2-m2,"'$ctime'",substr($0,n2))
}
{ print }
' m=51 n=80 m2=97 n2=126 file > file.new &&
mv file.new
注意,有其他(更简单的)方法来实现问题中实施的he替换。这与问题中描述的方法最为相似
使用SED,更换更容易:
ctime=$(date +%Y-%m-%dT%H:%M:%S.%3N-00:00)
fifteen_min_ago=$(date -d "15 mins ago" +%Y-%m-%dT%H:%M:%S.%3N-00:00)
sed -e 's/"start_date": "[^"]*"/"start_date": "'$ctime'"/' \
-e 's/"end_date": "[^"]*"/"end_date": "'$fifteen_min_ago'"/' < file > file.new && mv file.new file
ctime=$(日期+%Y-%m-%dT%H:%m:%S.%3N-00:00)
十五分钟以前=$(日期-d“十五分钟以前”+%Y-%m-%dT%H:%m:%S.%3N-00:00)
sed-e的/“开始日期”:“[^”]*”/“开始日期”:“$ctime”/”\
-e's/“结束日期”:“[^”]*”/“结束日期”:“$十五分钟前”/”file.new和&mv file.new文件
可以将sed
与OP的偏移量(m
和n
)结合使用,不过我们需要做一些数学运算,以获得正确的偏移量供sed
使用
在本例中,我们将使用以下数据集:
$ cat xx
1 2 3
data 6789012345678901234567890
abcdefghijklmnopqrstuvwxyz
我们将应用以下替换:
- 在以
开头的行上^data
- 将位置10-12替换为
和XXX
- 将位置20-25替换为
yyyyy
sed
调用实现这一点,我们需要2组偏移量:
m=10 ; n=12
o=20 ; p=25
r1=XXX
r2=YYYYYY
但在进入sed
脚本之前,我们需要考虑:
- 对于第一个
模式匹配,我们希望保留位置1-9和13-EOL,并将从位置10开始的字符替换为长度为3的字符sed
- 对于第二个
模式匹配,我们希望保留位置1-19和26-EOL,并将从位置20开始的字符替换为长度为6的字符sed
sed
特定偏移量,如下所示:
m2=$((m-4-1)) # ( 10 - length('data') - 1 ) = 5 ; so length(data)=4 + 5 = 9 = end of first set of characters to keep
n2=$((n-m+1)) # ( 12 - 10 + 1 ) = 3
o2=$((o-4-1)) # ( 20 - length('data') - 1 ) = 15; so length(data)=4 + 15 = 19 = end of first set of characters to keep
p2=$((p-o+1)) # ( 25 - 20 + 1 ) = 6
现在,我们准备看看sed
解决方案:
$ set -xv # echo the `sed` command with all variables substituted with values
$ sed -E "s/(^data.{${m2}}).{${n2}}(.*)$/\1${r1}\2/g; s/(^data.{${o2}}).{${p2}}(.*)$/\1${r2}\2/g" xx
其中:
-允许我们调试后续的set-xv
命令<代码>设置+xv将关闭sed
-对于以(^data.{${m2}})
开头的行,将前9个字符存储在缓冲区#1中;^data
+m2=5数据的长度
-匹配接下来的3个字符;将替换为{${n2}
r1的内容
-匹配行的其余部分并存储在缓冲区#2中(.*)$
-将行替换为buffer#1+\1${r1}\2
+buffer#2${r1}
-对于以(^data.{${o2}})
开头的行,将前19个字符存储在缓冲区#1中;^data
+o2=15数据的长度
-匹配接下来的6个字符;将替换为{${p2}
r2的内容
-匹配行的其余部分并存储在缓冲区#2中(.*)$
-将行替换为buffer#1+\1${r2}\2
+buffer#2${r2}
+ sed -E 's/(^data.{5}).{3}(.*)$/\1XXX\2/g; s/(^data.{15}).{6}(.*)$/\1YYYYYY\2/g' xx
1 2 3
data 6789XXX3456789YYYYYY67890
abcdefghijklmnopqrstuvwxyz
其中:
- 以
开头的行向我们显示了实际的+sed
命令,所有变量都插入到混合中(这是事先运行sed
的结果)set-xv
- 输出的其余部分是带有所需字符串替换的输入文件
-i
标志将所有这些写回原始文件:
$ set +xv # turn off debugging
$ sed -i -E "s/(^data.{${m2}}).{${n2}}(.*)$/\1${r1}\2/g; s/(^data.{${o2}}).{${p2}}(.*)$/\1${r2}\2/g" xx
$ cat xx
1 2 3
data 6789XXX3456789YYYYYY67890
abcdefghijklmnopqrstuvwxyz
可以将
sed
与OP的偏移量(m
和n
)结合使用,不过我们需要做一些数学运算,以获得正确的偏移量供sed
使用
在本例中,我们将使用以下数据集:
$ cat xx
1 2 3
data 6789012345678901234567890
abcdefghijklmnopqrstuvwxyz
我们将应用以下替换:
- 在以
开头的行上^data
- 将位置10-12替换为
和XXX
- 将位置20-25替换为
yyyyy
sed
调用实现这一点,我们需要2组偏移量:
m=10 ; n=12
o=20 ; p=25
r1=XXX
r2=YYYYYY
但在进入sed
脚本之前,我们需要考虑:
- 对于第一个
模式匹配,我们希望保留位置1-9和13-EOL,并将从位置10开始的字符替换为长度为3的字符sed
- 对于第二个
模式匹配,我们希望保持位置1-19和26-EOL,并替换从@posi开始的字符sed
awk -i inplace ' BEGIN { ctime = strftime("%Y-%m-%dT%H:%M:%S.%3N-00:00") fifteen_min_ago = strftime("%Y-%m-%dT%H:%M:%S.%3N-00:00",systime()-(15*60)) } match($0,/(^\s*data.*"start_date":[^"]*")([^"]+)(.*end_date":[^"]*")([^"]+)(.*)/,a) { $0 = a[1] fifteen_min_ago a[3] ctime a[5] } { print } ' file
$ cat file data = '{\n"feature_name": "ALL",\n"start_date": "2020-06-07T08:34:00.000-06:00",\n"end_date": "2020-06-08T13:35:00.000-06:00",\n"product": "SAEP",\n"limit":1000\n}' $ awk -i inplace ' BEGIN { ctime = strftime("%Y-%m-%dT%H:%M:%S.%3N-00:00") fifteen_min_ago = strftime("%Y-%m-%dT%H:%M:%S.%3N-00:00",systime()-(15*60)) } match($0,/(^\s*data.*"start_date":[^"]*")([^"]+)(.*end_date":[^"]*")([^"]+)(.*)/,a) { $0 = a[1] fifteen_min_ago a[3] ctime a[5] } { print } ' file $ cat file data = '{\n"feature_name": "ALL",\n"start_date": "2020-06-13T13:56:46.3N-00:00",\n"end_date": "2020-06-13T14:11:46.3N-00:00",\n"product": "SAEP",\n"limit":1000\n}'