在文本文件中插入或更新一行
Insert or update a row in a text file
我想将一个值写入带有时间戳的文本文件。 data/value 每隔几分钟更新一次,但我只想记录最后一个值及其日期。第二天,我想重新开始换行,但要保留以前的值。然后将输出图表显示每日值。
我可以用 if, then, else 循环来做到这一点,但我想还有更优雅的 awk、sed、'something' 解决方案。
这将由 cron 作业 运行。
第 1 天。
每 5 分钟插入一行 $date, $value
在同一天继续更新该行
第 2 天
插入新行并重复
期望输出
第 1 天上午 10 点
2021-08-17, 5.20
第 1 天晚上 11 点
2021-08-17, 12.10
第 2 天上午 10 点
2021-08-17, 12.10
2021-08-18, 4.90
第 2 天晚上 11 点
2021-08-17, 12.10
2021-08-18, 13.10
使用两个不同的 cronjob 条目。在每天开始时运行的一个,它使用 ed
或其他任何方式向文件添加新行:
# Something that sets date and value here
printf "%s\n" '$a' "$date, $value" . w | ed -s /your/file.txt
另一个每 5 分钟运行一次并用新值替换文件的当前最后一行:
# Something that sets date and value here
printf "%s\n" '$c' "$date, $value" . w | ed -s /your/file.txt
一个想法是 skip/ignore/delete 包含今天日期的行(如果存在),然后附加一个包含今天日期的新行。
示例数据文件:
$ cat date.log
2021-08-14, 23.1
2021-08-15, 17.3
2021-08-16, 9.3
$ today=$(date '+%Y-%m-%d')
$ echo $today
2021-08-17
$ newvalue=13.2
实现此逻辑的一个 sed
想法:
$ sed -i -n -e "/^${today}, .*$/"'!p' -e '$a'"${today}, ${newvalue}" date.log
其中:
-i -n -e
- -i
nplace更新源文件,-n
禁止自动打印patternspace,-e
指定一段脚本
"/^${today}, .*$/"
- 搜索匹配的模式(行首)+ ${today}
+ ,
+ 行的其余部分;需要使用双引号,以便 ${today}
被替换为它的实际值
'!p'
- 反向模式搜索和打印行(即,打印除匹配 ^${today}, .*$
的行之外的所有内容);需要使用单引号,因为双引号中的 !p
将替换为以字母 p
开头的最后一个历史命令
-e '$a'
- 找到文件结尾 ($
) 和 a
追加以下字符串的另一段脚本;必须使用单引号,这样 bash
就不会尝试用变量 a
的内容替换文字 $a
"${today}, ${newvalue}"
- 要附加到文件末尾的字符串
如果我们在 sed
调用前加上 set -xv
(启用调试模式),我们会在控制台看到以下内容:
+ sed -i -n -e '/^2021-08-17, .*$/!p' -e '$a2021-08-17, 13.2' date.log
我们文件的内容:
$ cat date.log
2021-08-14, 23.1
2021-08-15, 17.3
2021-08-16, 9.3
2021-08-17, 13.2 # new line appended to file
再运行几次(在发出 set +xv
以禁用调试模式后):
$ newvalue=32.7
$ sed -i -n -e "/^${today}, .*$/"'!p' -e '$a'"${today}, ${newvalue}" date.log
$ cat date.log
2021-08-14, 23.1
2021-08-15, 17.3
2021-08-16, 9.3
2021-08-17, 32.7 # updated (really deleted and appended)
$ newvalue=73.xxx
$ sed -i -n -e "/^${today}, .*$/"'!p' -e '$a'"${today}, ${newvalue}" date.log
$ cat date.log
2021-08-14, 23.1
2021-08-15, 17.3
2021-08-16, 9.3
2021-08-17, 73.xxx # updated (really deleted and appended)
$ today='2021-09-23'
$ newvalue=7.25
$ sed -i -n -e "/^${today}, .*$/"'!p' -e '$a'"${today}, ${newvalue}" date.log
$ cat date.log
2021-08-14, 23.1
2021-08-15, 17.3
2021-08-16, 9.3
2021-08-17, 73.xxx
2021-09-23, 7.25 # new line appended to file
使用 GNU awk 的 -i inplace
capable version:
$ gawk -i inplace -v d=2021-08-17 -v v=12.20 ' # new data in parameters
@load "filefuncs" # for stat to detect missing file
BEGIN {
if(ARGC==1) # if no file given
exit 1 # exit with an error
FS=OFS=", " # set the field separators
# d=strftime("%F") # no need parameterize the date
if(stat(ARGV[1],fdata)<0) { # if given file does not exist
print d,v > ARGV[1] # create it
exit # and exit
}
}
{
if(NR>1)
print pd,pv # print previous data record
pd= # store current for next round
pv=
}
ENDFILE { # in the end
if(pd!=d) # if dates differ
print pd,pv # print previous
print d,v # print given data
exit # to skip over following files
}' file
我想将一个值写入带有时间戳的文本文件。 data/value 每隔几分钟更新一次,但我只想记录最后一个值及其日期。第二天,我想重新开始换行,但要保留以前的值。然后将输出图表显示每日值。
我可以用 if, then, else 循环来做到这一点,但我想还有更优雅的 awk、sed、'something' 解决方案。
这将由 cron 作业 运行。
第 1 天。 每 5 分钟插入一行 $date, $value
在同一天继续更新该行
第 2 天 插入新行并重复
期望输出
第 1 天上午 10 点
2021-08-17, 5.20
第 1 天晚上 11 点
2021-08-17, 12.10
第 2 天上午 10 点
2021-08-17, 12.10
2021-08-18, 4.90
第 2 天晚上 11 点
2021-08-17, 12.10
2021-08-18, 13.10
使用两个不同的 cronjob 条目。在每天开始时运行的一个,它使用 ed
或其他任何方式向文件添加新行:
# Something that sets date and value here
printf "%s\n" '$a' "$date, $value" . w | ed -s /your/file.txt
另一个每 5 分钟运行一次并用新值替换文件的当前最后一行:
# Something that sets date and value here
printf "%s\n" '$c' "$date, $value" . w | ed -s /your/file.txt
一个想法是 skip/ignore/delete 包含今天日期的行(如果存在),然后附加一个包含今天日期的新行。
示例数据文件:
$ cat date.log
2021-08-14, 23.1
2021-08-15, 17.3
2021-08-16, 9.3
$ today=$(date '+%Y-%m-%d')
$ echo $today
2021-08-17
$ newvalue=13.2
实现此逻辑的一个 sed
想法:
$ sed -i -n -e "/^${today}, .*$/"'!p' -e '$a'"${today}, ${newvalue}" date.log
其中:
-i -n -e
--i
nplace更新源文件,-n
禁止自动打印patternspace,-e
指定一段脚本"/^${today}, .*$/"
- 搜索匹配的模式(行首)+${today}
+,
+ 行的其余部分;需要使用双引号,以便${today}
被替换为它的实际值'!p'
- 反向模式搜索和打印行(即,打印除匹配^${today}, .*$
的行之外的所有内容);需要使用单引号,因为双引号中的!p
将替换为以字母p
开头的最后一个历史命令
-e '$a'
- 找到文件结尾 ($
) 和a
追加以下字符串的另一段脚本;必须使用单引号,这样bash
就不会尝试用变量a
的内容替换文字 "${today}, ${newvalue}"
- 要附加到文件末尾的字符串
$a
如果我们在 sed
调用前加上 set -xv
(启用调试模式),我们会在控制台看到以下内容:
+ sed -i -n -e '/^2021-08-17, .*$/!p' -e '$a2021-08-17, 13.2' date.log
我们文件的内容:
$ cat date.log
2021-08-14, 23.1
2021-08-15, 17.3
2021-08-16, 9.3
2021-08-17, 13.2 # new line appended to file
再运行几次(在发出 set +xv
以禁用调试模式后):
$ newvalue=32.7
$ sed -i -n -e "/^${today}, .*$/"'!p' -e '$a'"${today}, ${newvalue}" date.log
$ cat date.log
2021-08-14, 23.1
2021-08-15, 17.3
2021-08-16, 9.3
2021-08-17, 32.7 # updated (really deleted and appended)
$ newvalue=73.xxx
$ sed -i -n -e "/^${today}, .*$/"'!p' -e '$a'"${today}, ${newvalue}" date.log
$ cat date.log
2021-08-14, 23.1
2021-08-15, 17.3
2021-08-16, 9.3
2021-08-17, 73.xxx # updated (really deleted and appended)
$ today='2021-09-23'
$ newvalue=7.25
$ sed -i -n -e "/^${today}, .*$/"'!p' -e '$a'"${today}, ${newvalue}" date.log
$ cat date.log
2021-08-14, 23.1
2021-08-15, 17.3
2021-08-16, 9.3
2021-08-17, 73.xxx
2021-09-23, 7.25 # new line appended to file
使用 GNU awk 的 -i inplace
capable version:
$ gawk -i inplace -v d=2021-08-17 -v v=12.20 ' # new data in parameters
@load "filefuncs" # for stat to detect missing file
BEGIN {
if(ARGC==1) # if no file given
exit 1 # exit with an error
FS=OFS=", " # set the field separators
# d=strftime("%F") # no need parameterize the date
if(stat(ARGV[1],fdata)<0) { # if given file does not exist
print d,v > ARGV[1] # create it
exit # and exit
}
}
{
if(NR>1)
print pd,pv # print previous data record
pd= # store current for next round
pv=
}
ENDFILE { # in the end
if(pd!=d) # if dates differ
print pd,pv # print previous
print d,v # print given data
exit # to skip over following files
}' file