我有简单的脚本,看起来像
for file in `ls -rlt *.rules | awk '{print $9}'`
do
cat $file | awk -F"|" -v DATE=$(date +%Y"_"%m"_"%d) '!$3{$3=DATE} !$4{$4=DATE} 1' OFS="|" $file
done
如何将awk的输出重定向到正在读取的同一文件以执行操作。
文件在运行上面的脚本之前有数据
123|test||
运行脚本文件后应该有像
这样的数据123|test|2017_04_05|2017_04_05
答案 0 :(得分:2)
您无法像这样动态更换文件,主要是因为增加了。
方法是使用临时文件,然后替换当前:
for file in `ls -1 *.rules `
do
TMP_FILE=/tmp/${file}_$$
awk -F"|" -v DATE=$(date +%Y"_"%m"_"%d) '!$3{$3=DATE} !$4{$4=DATE} 1' OFS="|" $file > ${TMP_FILE}
mv ${TMP_FILE} $file
done
答案 1 :(得分:1)
我会修改Michael Vehrs,否则回答如下:
ls -rt *.rules | while read file
do
TMP_FILE="/tmp/${file}_$$"
awk -F"|" -v DATE=$(date +%Y"_"%m"_"%d) \
'!$3{$3=DATE} !$4{$4=DATE} 1' OFS="|" "$file" > "$TMP_FILE"
mv "$TMP_FILE" "$file"
done
您的问题使用 ls (1)按时间排序文件,最早排序。以上保留了该财产。我删除了{}大括号,因为如果变量名没有被插值,它们就不会在shell脚本中添加任何内容,并引用来处理包含空格的文件名。
如果时间顺序不重要,我会考虑一个由内而外的解决方案:在awk中,写入临时文件而不是标准输出,然后使用system
重命名它一个END
块。然后,如果出现问题,您的输入将被保留。
答案 2 :(得分:0)
首先,当您需要的唯一内容是文件名时,使用ls -rlt
和awk
的组合是愚蠢的。您甚至不需要ls
因为 shell glob 由 shell 扩展,而不是ls
。只需使用for file in *.rules
即可。由于每个文件的日期似乎相同(除非你在午夜运行命令),所以提前计算它就足够了:
date=$(date +%Y"_"%m"_"%d)
for file in *.rules
do
TMP_FILE=$(mktemp ${file}_XXXXXX)
awk -F"|" -v DATE=${date} '!$3{$3=DATE} !$4{$4=DATE} 1' OFS="|" $file > ${TMP_FILE}
mv ${TMP_FILE} $file
done
但是,由于awk
也知道它正在读取哪个文件,你可以这样做:
awk -F"|" -v DATE=$(date +%Y"_"%m"_"%d) \
'!$3{$3=DATE} !$4{$4=DATE} { print > FILENAME ".tmp" }' OFS="|" *.rules
rename .tmp "" *.rules.tmp