![带有通配符的管道头部和尾部](https://linux22.com/image/201760/%E5%B8%A6%E6%9C%89%E9%80%9A%E9%85%8D%E7%AC%A6%E7%9A%84%E7%AE%A1%E9%81%93%E5%A4%B4%E9%83%A8%E5%92%8C%E5%B0%BE%E9%83%A8.png)
我在同一目录中有几个文件,我想打印连续间隔的某些行,例如从第 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
使用*.txt
glob 循环遍历所有文件,然后为每个文件打印一个标头并执行 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.txt
或ORS=.txt
......)。
在第一种情况下,我们通过使用前缀来解决这个问题./
(稍后我们将其删除)substr(FILENAME, 3)
,在第二种情况下(向其传递一个空文件:/dev/null,但使用-E
时不会处理赋值参数)。-E