使用FNR和NR在awk

使用FNR和NR在awk

我想添加一个像这样的分隔符“==============”和一个空白的新行

我尝试这样做,但失败并导致 CPU 使用率很高。我的意思是,当我运行脚本时,CPU 旋转速度很快且噪音很大

这需要用于大约 100000 个文本文件。

这是我使用的代码

#!/bin/bash
for F in *.txt ; do
    type "$F"
    echo .
    echo ========
    echo . 
done >> Combined.txt;

请指教

答案1

我将简化您的命令如下:

  #!/bin/bash
  for file in *.txt; do
  cat $file >> Combined.txt
  printf '\n\n=========\n\n' >> Combined.txt
  done

答案2

如果您要对数千个文件执行此操作,您可能希望避免每个文件运行多个命令。使用 GNU awk

printf '%s\0' ./*.txt | xargs -r0 gawk '
  BEGINFILE {if (NR) print "\n==========\n"};1' > combined.out

如果您要将输出文件放在同一目录中,请不要.txt为其提供扩展名,否则它将被选为输入文件并导致无限循环(可能首先是您的问题)。

或者使用内置的 shell,cat例如ksh93

#! /bin/ksh93 -
firstpass=true
for file in *.txt; do
  "$firstpass" || print '\n===========\n'
  firstpass=false
  command /opt/ast/bin/cat < "$file"
done > combined.out

循环中的所有这些命令都是内置的,因此运行它们不涉及分叉新进程或加载外部可执行文件,因此这将使性能可以接受。

答案3

使用FNRNRawk

#!/bin/bash

outfile="$( mktemp combined.txt.XXXXXX )"

echo "Output file: ${outfile}"

awk 'FNR==1 && NR>1 { printf("\n%s\n\n","========") } 1' *.txt > "${outfile}"

echo "Finished."

逐行描述:

outfile="$( mktemp combined.txt.XXXXXX )"

用于mktemp创建具有唯一名称(例如 )的空新文件combined.txt.HDpgMn。您可以使用更多X字符来获得更长的随机后缀。将命令括在"$(...中)"以将新文件的名称存储在变量 中outfile

echo "Saving to file: ${outfile}"

打印输出文件的名称。 (脚本完成后,您可能希望重命名输出文件以删除 . 后面的随机字符串.txt。)

awk 'FNR==1 && NR>1 { printf("\n%s\n\n","========") } 1' *.txt > "${outfile}"

打印...

  • 一个空行,
  • 一小行“=”字符,
  • 和另一个空行

...在每个输入文件的开头,第一个输入文件除外。 FNR计算输入文件的行数,并在每个文件的开头重置。 NR计算行号并且不重置。

在该awk语句中,1右单引号之前的TRUE每行计算结果为,并执行打印该行的默认操作。 (换句话说,awk '1'工作原理类似于cat。)

echo "Finished."

脚本完成后通知用户。 (并非绝对必要,因为无论如何您都会看到命令提示符,但这并没有什么坏处。)

答案4

为什么不简单地

printf "\n\n=====\n\n" > XTMP
cat $(printf "%s XTMP " *.txt) > combined.tmp

将分隔符放入临时文件中,并利用 的printf功能为其找到的每个参数重复格式化字符串,因此cat命令将如下所示

cat 1.txt XTMP 2.txt XTMP ... n.txt XTMP

不过,您可能会遇到系统限制(例如 LINE_MAX)...

相关内容