Как правильно использовать хвост для объединения всех скрытых файлов

Я сделал простой сценарий оболочки, который покажет вам, сколько раз наша система перезагружалась в день.

#!/bin/bash
day=$(date | awk {'print $1 " " $3 " " $2'})
echo $day
reboot_times=$(last reboot | grep "$day" | wc -l)
echo $reboot_times times rebooted

выход

Ср

2 раза перезагрузился

2
23.06.2021, 19:26
1 ответ

В zshи GNUtail(не все хвостовые реализации могут принимать более одного аргумента имени файла, и не все из них будут отображать имена файлов):

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

-vпо-прежнему печатать имена файлов, даже если есть только один файл, Dдля dotglob, Nдля nullglob, используя анонимную функцию, которая передает расширение этого глобуса и проверяет особый случай текущего каталога быть пустым.

</dev/nullчастично смягчает тот факт, что GNU tailпри передаче имени файла с именем -вместо этого будет читать стандартный ввод. Здесь мы просто запрещаем ему читать стандартный ввод, но он по-прежнему не будет читать файл с именем -. Другой подход заключается в использовании "${@/#%-/./-}"вместо "$@"для замены -на ./-, но это также будет означать, что вы увидите ==>./- <==вместо ==> - <==для файла -(все же, вероятно, лучше, чем==> standard input <==).

Вы также можете добавить квалификатор.(или-.)glob, чтобы ограничить обычными файлами только во избежание ошибок или еще хуже, если есть каталоги или другие типы не -обычных файлов. файлы в текущем каталоге(*(ND-.)).

То же самое с ksh93и GNUtail:

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

То же самое с bashи GNUtail:

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

Или с GNU tailи любым POSIX sh(, включая zsh, но только в shэмуляции ), также ограничение на обычные или символические ссылки на обычные файлы и замена -на ./-, но потенциально обрабатываем файлы в другом порядке, так как мы делаем .*одни перед другими:

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

Или вы можете использовать GNUawk(здесь сzsh):

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

awkимеет ту же проблему, что и tailс -, а также с именами файлов, содержащими =. Мы работаем с обоими, добавляя префикс ./, который мы удаляем при отображении. Обратите внимание, что awk добавляет символ новой строки, если он отсутствует в конце файлов.

Или используйте цикл:

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

(catимеет ту же проблему, что и -,который мы обходим, передавая файл на стандартный ввод вместо аргументов)

4
28.07.2021, 11:22

Теги

Похожие вопросы