将循环输出重定向到当前读取文件

时间:2017-04-05 07:08:38

标签: shell awk

我有简单的脚本,看起来像

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

3 个答案:

答案 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 -rltawk的组合是愚蠢的。您甚至不需要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