例子

例子

我目前正在使用

watch head -n 17 *

它有效,但也显示了 17 号之前的所有线路。基本上,我只想显示用我当前的方法显示的每个文件的最后一行。我怎样才能做到这一点?

例子

为了举例,让我们减少行数。到 7. 所以:

示例文件:

1
2
3
4
5
6
7
8

这一行:

watch head -n 7 *

输出

1
2
3
4
5
6
7

我想要的地方:

7

答案1

使用 GNU awk

watch -x gawk '
  FNR == 17 {nextfile}
  ENDFILE   {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}' ./*

其输出如下:

        ./file1[17] line17
  ./short-file2[05] line 5 is the last

请注意, glob 仅在调用./*时展开一次。watch

您的watch head -n 17 *漏洞是一个任意命令注入漏洞,因为它的扩展*实际上被 shell 解释为 shell 代码,watch调用解释其参数与空格的串联。

如果当前目录中有一个文件被调用$(reboot),它将重新启动。

使用-x,我们告诉watch跳过 shell 并直接执行命令。或者,你可以这样做:

watch 'exec gawk '\''
  FNR == 17 {nextfile}
  ENDFILE   {if (FNR) printf "%15s[%02d] %s\n", FILENAME, FNR, $0}'\'' ./*'

用于watch运行一个 shell,该 shell 将./*在每次迭代时扩展该 glob。watch foo bar实际上与 相同watch -x sh -c 'foo bar'。使用时watch -x,您可以指定所需的 shell,例如选择一个更强大的 shell,zsh可以执行递归通配并限制为常规文件:

watch -x zsh -c 'awk '\''...'\'' ./**/*(.)'

如果没有gawk,您仍然可以执行以下操作:

watch '
  for file in ./*; do
    [ -s "$file" ] || continue
    printf "%s: " "$file"
    head -n 17 < "$file" | tail -n 1
  done'

给出如下输出:

./file1: line17
./short-file2: line 5 is the last

但这会降低效率,因为它意味着每个文件运行多个命令。

答案2

在这两个例子中结合head并喜欢:tail

$ seq 1 80 | head -n 17 | tail -n 1
17

$ seq 1 10 | head -n 17 | tail -n 1
10

因此,为了解决您的实际问题,命令是:

watch 'for f in *; do head -n 17 -- "$f" 2>/dev/null | tail -n 1 ; done'

请注意该2>/dev/null部分,它是必需的,因为 * 将匹配目录和您可能无权读取的任何文件,这将产生您可能想要隐藏的错误消息。

答案3

另一种使用 find、exec 和 sed 的方法

watch find . -type f -name \"*\" -exec sh -c \'\( printf '%-50s ' {} \; sed -n 17p {}\)\' \\\;

相关内容