带有通配符的管道头部和尾部

带有通配符的管道头部和尾部

我在同一目录中有几个文件,我想打印连续间隔的某些行,例如从第 15 到第 20。

对于单个文件来说,这是可行的head -n20 file.txt | tail -n6,但是我如何让它适用于通配模式,例如,对于该目录中的所有 txt 文件*.txt

head -n20 *.txt | tail -n6 # this only crops results of head -n20

编辑1:我也知道 的解决方法for,但我希望学习如何以也适用于通配符的统一方式定义多个操作的管道。

ps 可能具有标准标头,例如==> file.txt <==head通配符tail结合使用时给出的标头,这要求太多了。

pps 使用 ubuntu,但 UNIX 范围的方法会更好。

答案1

这个单线怎么样?

for f in *.txt; do echo -e "\n==> $f <=="; head -n 20 "$f" | tail -n 6; done

当在当前目录中运行时,它.txt使用*.txtglob 循环遍历所有文件,然后为每个文件打印一个标头并执行 head、tail 操作。

答案2

请注意,虽然标准head可以采用多个文件名作为参数并输出这些==> filename <==标头,标准tail只能采用一个文件名作为参数(如果传递多个文件名,则行为未指定。

在这里,您可以使用以下命令来代替 shell 循环gawk

gawk 'BEGINFILE{print sep"==> "substr(FILENAME, 3)" <=="; sep = "\n"}
      FNR >= 15
      FNR == 20 {nextfile}' ./*.txt

你可以把它变成一个函数:

linerange() (
  min=$1 max=$2
  shift 2
  exec gawk -v min="$min" -v max="$max" -e '
    BEGINFILE{print sep"==> "FILENAME" <=="; sep = "\n"}
    FNR > max {nextfile}
    FNR >= min' -E /dev/null "$@"
)

进而:

linerange 15 20 *.txt

gawk,就像任何一个awk问题一样,形式的参数var=value被视为变量赋值而不是输入文件名。这意味着,如果您的某些.txt文件无法foo=bar.txt正常工作(您可能会产生更烦人的副作用,例如ARGC=0.txtORS=.txt......)。

在第一种情况下,我们通过使用前缀来解决这个问题./(稍后我们将其删除)substr(FILENAME, 3),在第二种情况下(向其传递一个空文件:/dev/null,但使用-E时不会处理赋值参数)。-E

相关内容