在打印行之前打印文件名

在打印行之前打印文件名

我使用以下 bash 函数打印文件中的特定范围行。

print-lines ()
  {
    na=$1
    nb=$2
    dir=$3

    find "$dir" \( -name \*.org -o -name \*.texi \)  \
      -exec awk -v a="$na" -v b="$nb"                \
             'FNR >= a && FNR <= b {print}' {} +
  }

我有两个这样的文件

foo:
a
b
c
d
e 

bar:
1
2
3
4
5

令命令为print-lines 2 4。我想要的结果是

==> foo <==

b
c
d

==> bar <==

2
3
4

答案1

如果仅当文件至少有$na行时才应打印文件名:

find . -name '*.csv' -exec awk -v a="$na" -v b="$nb" '
    FNR == a {print "==>", FILENAME, "<=="}
    a <= FNR && FNR <= b
' {} +

如果要为每个文件打印文件名而不管其内容如何,​​GNU awk 会很方便

find . -name '*.csv' -exec gawk -v a="$na" -v b="$nb" '
    BEGINFILE {print "==>", FILENAME, "<=="}
    a <= FNR && FNR <= b
' {} +

答案2

head如果您喜欢和打印的标题tail,您可以让其中之一打印它。要获取从 A 到 B 的行(从 1 开始计数),首先告诉从tailA 行开始 ( +A),然后告诉 head 保留前 B-A+1 行,再加上 1 行作为标题行。

tail -n "+$na" -v -- "$filename" | head -n $((nb - na + 2))

从 find 调用,每个文件后面有一个空行(几乎与headtail一样 - 这里的代码在最后添加一个空行):

find … -exec sh -c 'tail -n "+$1" -v -- "$0" | head -n $(($2 - $1 + 2)); echo' {} "$1" "$2" \;

答案3

您可以让findby 语句进行打印printf。请注意, in-exec +不再可能像这样,您必须使用 的具体情况调用awk

print-lines () {
    na=$1
    nb=$2
    dir=$3

    find "$dir" \( -name \*.org -o -name \*.texi \)  \
    -printf '==> %p <==\n\n' \
    -exec awk -v a="$na" -v b="$nb" 'FNR >= a && FNR <= b' '{}' \; \
    -printf '\n'    
  }

可能比仅使用解决方案性能稍差awk

答案4

使用GNU sed我们使用 -s 选项将多个文件提供给 sed 并单独处理。

find "$dir" -type f \
  \( -name "*.texi" -o -name "*.org" \) \
  -exec sed -sne "
    ${na}{x;s/.*/==>/p;F;s//<==/p;x;}
    $na,${nb}p
" {} +;

Python结合pathlib模块来遍历层次结构和itertools来切片文件

python3 -c 'import pathlib, itertools, sys
na,nb,dir = sys.argv[1:]
p = pathlib.Path(dir)
for q in p.glob("**/*"):
  if q.suffix in [".texi",".org"] and q.is_file():
    with open(q.name) as f:
      L = [l.rstrip("\n") for l in itertools.islice(f, int(na)-1, int(nb))]
    if len(L) > 0:
      print("==>",q.name,"<==")
      print(*L,sep="\n")
' 2 4 .

相关内容