【问题标题】:how to sort the file in awk如何在awk中对文件进行排序
【发布时间】:2012-08-04 06:49:58
【问题描述】:

我有一个小问题。我需要根据文件的某些起始字符串对文件进行排序。例如按照数字 04、05 或 06 的这种形式:

04..............
................
................
05..............
................
................
06..............
................
................ etc.. 

这是我的 awk 代码:http://pastebin.com/dLsWkV3q

或者就在这里:

echo "starting...input file"
read file
echo "reading file..."                                                  

echo "... now sorting..."
cat $file | awk '{
if($1=="04"){
print >> "04_file.txt";
}
if($1=="05"){
print >> "05_file.txt";
 }

if($1=="06"){
print >> "06_file.txt";
 }
}'

echo "finished, bye?"
read wait
echo "bye"

目标是我需要多个仅包含相应块的文件,例如上面的示例:结果我将有 3 个文件。 04_file.txt05_file.txt06_file.txt。并且05_file.txt 没有来自 04 块的任何行。最终的04_file.txt 文件将只有这个:

04..............
................
................

我的问题是它会将其他块也保存到 04_file.txt..

我将不胜感激。非常感谢

【问题讨论】:

  • 看起来你可以用 csplit 做到这一点?

标签: shell sorting awk


【解决方案1】:

我假设唯一以 04、05 等开头的行是分隔不同块的行:

awk '
    BEGIN { mode="unknown" }
    /^04/ { mode="04" }
    /^05/ { mode="05" }
    /^06/ { mode="06" }
          { if (mode != "unknown") print $0 >> sprintf("%s_file.txt", mode)}' < $file

awk 基本上是一个根据模式执行操作的环境。每个模式动作语句都有以下形式

pattern { action }

模式最简单的形式是匹配当前输入行的正则表达式。 BEGIN 是一种特殊情况,它在读取输入之前“匹配”,还有一个 END “模式”,它在输入文件被消耗后执行。

在执行时awk 逐行读取输入文件并执行模式与该行匹配的所有操作。在上面的代码中,如果输入行以 04、05 等开头 (^),则设置 mode 变量。最后一行(没有模式)匹配所有行,并将整行写入相应的文件。

我会尝试用一些伪代码来总结一下:

mode := "unknown"
for each line of input do
    if line starts with 04 then set mode to 04 endif
    if line starts with 05 then set mode to 05 endif
    if line starts with 06 then set mode to 06 endif

    # mode is now either "unknown" if no 04/05/06 pattern has been read
    # from the file yet or holds the most recently read block start (04/05/06)

    if mode is not "unknown" then
        append whole line to file named 'mode'_file.txt
    endif
endfor

如果您想更进一步,请查看手册页或浏览网页以获取 awk 介绍。在那里您还可以了解有关 pattern 部分的更多信息,它可以做的不仅仅是匹配上面示例中的当前输入行。


如果所有块都以两位数(任何数字)开头,则上面的代码可以缩短为

awk '
    BEGIN { mode="unknown" }
    /^[[:digit:]][[:digit:]]/ { mode=substr($0, 1, 2) }
          { if (mode != "unknown") print $0 >> sprintf("%s_file.txt", mode)}' < $file

【讨论】:

  • 是的,你是对的,以 04、05 开头的那些行是分隔块的。你能简要解释一下代码的作用吗? :(。我不想复制和粘贴..
  • so,if(mode!="unknown")的意思是如果当前行既不是04也不是05,那么它会取last mode作为文件名,把当前行写入那个文件,对吧?
  • 不,最后一行没有模式({} 前面的部分),并为每个输入行执行。我不知道您的输入文件是否不是以 04/05/06 行开头。这就是为什么我在开始时将模式设置为“未知”,并且只有在读取 04/05/06 行后才开始写入 dd_file.txt。
  • 模式保持不变,除非在文件中遇到新的 04/05/06。因此,如果 05 在 'aba' 上方的那一行,则该行转到 05_file.txt。
  • 我建议在调用 awk 脚本之前创建文件夹,然后在脚本中使用 sprintf("foldername/%s_file.txt", mode)
猜你喜欢
  • 2016-01-14
  • 2013-10-13
  • 2018-09-13
  • 2018-10-29
  • 1970-01-01
  • 2015-05-22
  • 1970-01-01
  • 2010-09-11
  • 2011-01-28
相关资源
最近更新 更多