如何正确使用 tail 来连接所有隐藏文件

如何正确使用 tail 来连接所有隐藏文件

问题

我希望能够:

  1. 连接目录中的所有文件(常规和隐藏),
  2. 但我还想在每个串联的开头显示每个文件的标题。

我在网上找到了一些解决方案,我可以用tail -n +1 * 2>/dev/null超级巧妙的技巧做#2,但它不包括隐藏文件,就像我要做的那样:cat * .* 2>/dev/null 或者甚至head * .* 2>/dev/null

cat 命令可以解决问题,但不包含文件名,并且 head 命令不会打印/连接每个文件的全部内容。

问题

有没有办法做我需要做的事情tail如果不是,什么是达到相同结果/输出的良好替代品。

更新一个例子

尝试连接所有文件(常规文件和隐藏文件)时的 tail 命令


[kevin@PC-Fedora tmp]$ ls -la
total 8
drwx------   2 user user 4096 Jun 23 09:24 .
drwxr-xr-x. 54 user user 4096 Jun 23 08:21 ..
-rw-rw-r--   1 user user    0 Jun 23 09:24 .f1
-rw-rw-r--   1 user user    0 Jun 23 09:24 f1
-rw-rw-r--   1 user user    0 Jun 23 09:24 .f2
-rw-rw-r--   1 user user    0 Jun 23 09:24 f2
-rw-rw-r--   1 user user    0 Jun 23 09:24 .f3
-rw-rw-r--   1 user user    0 Jun 23 09:24 f3
-rw-rw-r--   1 user user    0 Jun 23 09:24 .f4
-rw-rw-r--   1 user user    0 Jun 23 09:24 f4
-rw-rw-r--   1 user user    0 Jun 23 09:24 f5
[user@PC-Fedora tmp]$ tail -n +1 *
==> f1 <==

==> f2 <==

==> f3 <==

==> f4 <==

==> f5 <==
[user@PC-Fedora tmp]$ tail -n +1 * .*
==> f1 <==

==> f2 <==

==> f3 <==

==> f4 <==

==> f5 <==

==> . <==
tail: error reading '.': Is a directory
[user@PC-Fedora tmp]$ 


答案1

使用zshGNU tail(并非所有 tail 实现都可以采用多个文件名参数,并且并非所有这样做都会显示文件名):

() { (($# == 0)) || tail -vn +1 -- "$@" < /dev/null; } *(ND)

-v是仍然打印文件名,即使只有一个文件,D对于 dotglob,N对于 nullglob,使用一个匿名函数,该函数传递该 glob 的扩展并检查当前目录是否为空的特殊情况。

</dev/null是为了部分缓解这样的事实:GNUtail在传递名为 的文件名时-,将改为读取 stdin。在这里,我们只是阻止它读取 stdin,但它仍然不会读取名为-.另一种方法是使用代替 来"${@/#%-/./-}"替换"$@",但这也意味着您会看到而不是for文件(仍然可能比 更好)。-./-==> ./- <====> - <==-==> standard input <==

您可能还需要添加.(或-.) glob 限定符来限制常规的仅当当前目录 ( ) 中存在目录或其他类型的非常规文件时,才可以避免出现错误或更糟糕的情况*(ND-.)

ksh93与GNU相同tail

(
  FIGNORE='@(.|..)'
  set -- ~(N)*
  (($# == 0)) || tail -vn +1 -- "$@" < /dev/null
)

bash与GNU相同tail

(
  setopt -s nullglob dotglob
  set -- *
  (($# == 0)) || tail -vn +1 -- "$@" < /dev/null
)

或者使用 GNUtail和任何 POSIX sh(包括zsh,但仅在sh仿真中),也限制为常规文件或符号链接到常规文件并替换-./-,但可能以不同的顺序处理文件,因为我们.*在其他文件之前处理文件:

(
  set --
  for file in .* *
    [ -f "$file" ] || continue
    [ "$file" = - ] && file=./-
    set -- "$@" "$file"
  done
  [ "$#" -eq 0 ] || exec tail -n +1 -- "$@"
)

或者你可以使用 GNU awk(这里使用zsh):

() {
  (( $# == 0 )) ||
    gawk 'BEGINFILE{
            print sep "==> "substr(FILENAME, 3)" <=="
            sep = "\n"
          }
          {print}' "$@"
} *(ND-.)

awktail包含.-​我们通过添加在显示时删除的前缀来=解决这两个问题。./请注意,如果文件末尾缺少换行符,awk 会添加一个换行符。

或者使用循环:

sep=
for f (*(ND-.)) {
  print -r "$sep==> $f <=="
  sep=$'\n'
  cat < $f
}

cat与 存在同样的问题-,我们通过在 stdin 而不是参数上传递文件来解决这个问题)

相关内容