【问题标题】:Awk, end of line in scriptawk,脚本中的行尾
【发布时间】:2012-09-11 22:14:48
【问题描述】:

我只是第一次尝试使用 awk,并且有一个可能很简单的问题。我正在尝试列出一个目录并根据字符串从列表中提取一些信息。我正在尝试的 bash 脚本是:

 ls *.hdf > temporary.list
 nom2=`awk 'BEGIN {FS = "." } ; { $1 ~ /'$year$month'/ } { print $2 }' temporary.list `
 file=$year$month.$nom2.hdf 
 file2=$year$month.hdf

for 循环中年份和月份的变化(1981 到 1985 和 01 到 12)。 temporary.list 文件由 12 行组成,例如:

198201.s04m1pfv51-bsst.hdf
198202.s04m1pfv51-bsst.hdf
198203.s04m1pfv51-bsst.hdf
198204.s04m1pfv51-bsst.hdf
198205.s04m1pfv51-bsst.hdf
198206.s04m1pfv51-bsst.hdf
198207.s04m1pfv51-bsst.hdf
198208.s04m1pfv51-bsst.hdf
198209.s04m1pfv51-bsst.hdf
198210.s04m1pfv51-bsst.hdf
198211.s04m1pfv51-bsst.hdf
198212.s04m1pfv51-bsst.hdf

我想根据年月选择文件。问题是我的 awk 句子似乎没有将不同的行作为不同的寄存器,我想。脚本的输出是:

nom2 = h s04m1pfv51-bsst h s04m1pfv51-bsst h s04m1pfv51-bsst h
s04m1pfv51-bsst h s04m1pfv51-bsst h s04m1pfv51-bsst h s04m1pfv51-bsst
s04m1pfv51-bsst s04m1pfv51-bsst s04m1pfv51-bsst s04m1pfv51-bsst
s04m1pfv51-bsst 

file = 198201.h s04m1pfv51-bsst h s04m1pfv51-bsst h
s04m1pfv51-bsst h s04m1pfv51-bsst h s04m1pfv51-bsst h s04m1pfv51-bsst
h s04m1pfv51-bsst s04m1pfv51-bsst s04m1pfv51-bsst s04m1pfv51-bsst
s04m1pfv51-bsst s04m1pfv51-bsst.hdf 

file2= 198201.hdf

可能是一些简单的语法错误,任何帮助将不胜感激。

谢谢

【问题讨论】:

  • 您希望从脚本中获得什么输出?

标签: awk


【解决方案1】:

您需要向awk 提供您需要它知道的变量。
要将变量传递给 awk,请为每个变量使用 -v

awk -v y="$year" -v m="$month" 'BEGIN { FS = "." } $1 == y m { print $2 }' file

awk 变量可以直接使用,不需要$
print 一样,它们之间的空格将被忽略,必须引用真实的空格。 所以它现在的方式是检查第一个字段 ($1) 是否完全匹配 (==) 'y m' 扩展为 '${year}${month}'。如果匹配发生,则打印第二个字段 ($2)。


请记住,awk 逻辑块的格式为

condition { action [; action ..] }

注意condition周围没有花括号
您也不需要在块之间使用;,只需要在动作之间,但它们也不会受到伤害。
所以,{ $1 ~ /'$year$month'/ } 不会像它写的那样做任何事情。


说了这么多,我会选择纯Bash 来做你正在做的事情:

while IFS='.' read -r ym f e
do 
    printf '%8s: %s\n' "year"  "${ym%??}"   \
                       "month" "${ym#????}" \
                       "file"  "$f"         \
                       "ext"   "$e"
done < file

【讨论】:

  • { $1 ~ /'$year$month'/ } 确实做了一些事情。第一个单引号结束一个单引号字符串,以便$year$month 替换工作......
  • 在我的脚本中传递变量是可以的,我只是展示了 awk 部分。关键是 nom2 应该只显示一个值,对应于年份和月份,我得到的是 nom2 s04m1pfv50-bsst-16b s04m1pfv50-bsst-16b s04m1pfv50-bsst-16b s04m1pfv50- bsst-16b s04m1pfv50-bsst-16b s04m1pfv50-bsst-16b s04m1pfv50-bsst-16b s04m1pfv50-bsst-16b s04m1pfv50-bsst-16b s04m1pfv50-bsst-16b s04m1pfv50-bsst-16b s04m1pfv50-bsst-16b showing the 12月值
  • 如果我将 grep $year$month 添加到目录列表(temporary.list 是一个单行文件),那么它可以正常工作并正确提取我需要的值。但我认为这应该用 awk 来完成。
  • @jens 对,这就是将变量传递给awk的方式
  • @pacomet 正确,因为条件就像一个空的 if 语句和 print $2 无条件打印。我在回答中告诉过你:{ $1 ~ /'$year$month'/ } 就像if ($1 ~ /'$year$month'/) /*empty*/;
【解决方案2】:

像在 bash 脚本中那样解析文件列表是一个坏习惯,因为它与文件名中可能出现的许多特殊字符不兼容。就像语法规则一样,只有在你熟悉规则的情况下才能打破规则。 :) for 循环是处理文件的更好构造:

#!/bin/bash

year=1982
month=9

for filename in $(printf "%04d%02d" "$year" "$month").*.hdf; do
  nom2=${filename#*.}
  nom2=${nom2%.*}
  file2=${filename%%.*}.hdf
  printf "file=%s\nnom2=%s\nfile2=%s\n\n" "$filename" "$nom2" "$file2"
done

这就是你要找的吗?请注意,使用%# 的参数扩展可以在传统的bourne shell 和bash 中使用,因此它非常便携。

如果你真的想使用 awk,你还有很多选择。

#!/bin/bash

year=1982
month=9

for filename in $(printf "%04d%02d" "$year" "$month").*.hdf; do
  nom2=$(awk -vym="^$year$month." -vf="$filename" 'BEGIN{if(f~ym){sub(/\..*/,"",f);print f}}')
  file="$nom2.hdf"
  printf "file=%s\nnom2=%s\nfile2=%s\n\n" "$filename" "$nom2" "$file2"
done

请注意,使用printf 格式化日期可以让您轻松处理带有前导零的个位数月份。

【讨论】:

  • 我无法弄清楚 sub 在这里是如何工作的。它还警告靠近 sub. 的双引号 /,",f 中的错误。
  • Wups,错字(现已修复) - 我错过了 sub() 中的一句话。这个想法是它寻找一个从第一个点开始到行尾的模式,用一个空字符串替换它。它在其中执行此操作的工作区是“f”变量,之前用-v 设置。
猜你喜欢
  • 2021-11-11
  • 2018-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-15
  • 2014-08-19
  • 2013-08-17
相关资源
最近更新 更多