Bash — рисовать вертикальную линию за строками переменной длины

Это виртуальная машина? Или физическую систему на блейд-оборудовании?

Блейд-оборудование некоторых производителей позволяет синхронизировать аппаратные часы каждого блейд-модуля с часами процессора управления корпуса блейд-сервера. По крайней мере, на (некоторых моделях блейд-оборудования )Fujitsu этот параметр синхронизации был включен по умолчанию. Чтобы отключить его, вам нужно было получить доступ к настройкам BIOS блейда.

Виртуальные машины обычно синхронизируют свои виртуальные аппаратные часы в соответствии с часами физической хост-системы во время инициализации ВМ, поскольку виртуальная машина не может иметь реальных физических аппаратных часов. Если у вашего хостинг-провайдера в основном системы Windows, синхронизация может быть настроена на использование местного времени, а не UTC.


И есть одна проблема, которая может повлиять как на физические, так и на виртуальные системы, особенно при использовании корпоративных дистрибутивов Linux:

До того, как появился инструмент hwclockи соглашение, указывающее, что RTC настраивается либо на UTC, либо на местное время в /etc/adjtime, существовало несколько -специфичных для дистрибутива способов сохранения этой настройки. Для обратной совместимости эти методы могут существовать. А корпоративные дистрибутивы особенно заинтересованы в обратной совместимости.

Это может вызвать проблемы, когда настройка UTC/local в /etc/adjtimeконфликтует с соответствующей устаревшей настройкой в ​​/etc/sysconfig/clock, /etc/default/rcSили аналогичной :initramfs дистрибутива может учитывать устаревший метод, в то время как hwclock, запускаемая системным администратором в интерактивном режиме, следует за командой /etc/adjtime, если она не переопределена -, и автоматически сохраняет новую настройку в/etc/adjtimeтолько , если используются опции --utcили --local.

Чтобы это исправить:

  • убедитесь, что /etc/adjtimeи любые устаревшие настройки в /etc/sysconfig/clock, /etc/default/rcSили аналогичные соответствуют тому, работают ли аппаратные часы в формате UTC или по местному времени,чтобы разные инструменты не давали разных интерпретаций
  • после этого обновите файл initramfs, чтобы убедиться, что процессы ранней загрузки используют те же настройки, что и остальная часть системы.

Если вы этого не сделаете, вы можете получить систему, часы которой смещаются ровно на величину текущего смещения UTC при каждой загрузке.

Если вам нужно свести к минимуму риск того, что это повторится снова, вы можете проверить, поддерживает ли ваш дистрибутив настройку устаревшей конфигурации UTC/localtime как «нейтральную», так что /etc/adjtimeбудет единственным источником правды в этом вопросе.. Поскольку сценарии запуска обычно получают доступ к аппаратным часам только через hwclock, устаревшая конфигурация может оказаться ненужной.

9
20.11.2019, 05:31
5 ответов

Вы можете напечатать строки без выравнивания и отформатировать вывод с помощью column -tи фиктивного символа-разделителя:

#!/bin/bash

while read -r line; do
  if [ -z "$line" ]; then
    echo
    continue
  fi
  printf '%s@| %%%s\n' "$line" "$((++n))"
done < file | column -e -s'@' -t | sed 's/ |/|/'

Здесь я добавил @в качестве фиктивного символа перед |, обозначающим конец столбца. Команда sedв конце используется для удаления одного дополнительного пробела перед |. Опция -eнужна для того, чтобы в выводе оставались пустые строки.

Выход:

c4-1 d e c            | %1
c d e c               | %2
e-2 f g2              | %3
e4 f g2               | %4
g8-4\( a-5 g f\) e4 c | %5
g'8\( a g f\) e4 c    | %6
c-1 r c2              | %7
c4 r c2               | %8
10
27.01.2020, 20:04

Используя awk+ GNU wc, предполагая, что все символы во входных данных имеют одинарную ширину -:

$ awk -v f="$(wc -L < ip.txt)" '{printf "%-*s | %%%s\n", f, $0, NR}' ip.txt
c4-1 d e c            | %1
c d e c               | %2
e-2 f g2              | %3
e4 f g2               | %4
g8-4\( a-5 g f\) e4 c | %5
g'8\( a g f\) e4 c    | %6
c-1 r c2              | %7
c4 r c2               | %8
9
27.01.2020, 20:04

просто для записи:(это ужасно медленно, но это была моя первая попытка использоватьwc -L)
определенно собираюсь получить ответ @Freddy, используя column!

#!/bin/bash

file="$1"

ll=$(wc -L < "$file")

while read -r line; do
    if [ -z "$line" ]; then
        echo
        continue
    fi
    sl=$(wc -L <<< "$line")
    if [ "$ll" = "$sl" ]; then
        as=$(echo "$ll - $sl" | bc)
    else
        as=$(echo "$ll - $sl + 1" | bc)
    fi
    space=$(printf '\ %.0s' $(seq "$as") )
    n=$((++n)) \
    && grep -vE "^$|^%" <<< "$line" \
    | sed "s/$/$space\ \|\ \%$(printf "%s" "$n")/"
done < "$file"

хотя работает с одним дополнительным пробелом:

c4-1 d e c             | %1
c d e c                | %2
e-2 f g2               | %3
e4 f g2                | %4
g8-4\( a-5 g f\) e4 c  | %5
g'8\( a g f\) e4 c     | %6
c-1 r c2               | %7
c4 r c2                | %8
2
27.01.2020, 20:04

Простой bash :работает с версией bash >= 4.0

#!/bin/bash
mapfile -t lines < file
max=0
for line in "${lines[@]}"; do
    max=$(( ${#line} > max ? ${#line} : max ))
done
for i in "${!lines[@]}"; do
    printf "%-*s | %%%d\n" $max "${lines[i]}" $((i+1))
done

Для старых версий bash замените файл карты на while -цикл чтения :это работает с версией 3.2

#!/bin/bash
lines=()
max=0
while IFS= read -r line || [[ -n "line" ]]; do
    lines+=("$line")
    max=$(( ${#line} > max ? ${#line} : max ))
done < file
for i in "${!lines[@]}"; do
    printf "%-*s | %%%d\n" $max "${lines[i]}" $((i+1))
done
4
27.01.2020, 20:04

Предполагая, что в данных нет @символов (, просто замените два @, используемых здесь, другим символом в этом случае):

$ awk -v OFS='@| %' '{ print $0, FNR }' file | column -s '@' -t
c4-1 d e c             | %1
c d e c                | %2
e-2 f g2               | %3
e4 f g2                | %4
g8-4\( a-5 g f\) e4 c  | %5
g'8\( a g f\) e4 c     | %6
c-1 r c2               | %7
c4 r c2                | %8

Это использует строку @| %в качестве разделителя выходных полей и печатает ввод, за которым следует номер строки каждой строки (, разделенной этим разделителем ), а затем использует columnдля выравнивания этого по @символов (они будут удалены ).


Если вам нравятся sedили неудобные регулярные выражения, вы всегда можете пронумеровать строки с помощью cat -nили nl -b a, а затем переместить номера строк в конец строки и вставить @| %с помощью sed, перед вызовомcolumn:

$ cat -n file | sed -E 's/^[[:blank:]]*([[:digit:]]+)[[:blank:]]*(.*)$/\2@| \%\1/' | column -s '@' -t
c4-1 d e c             | %1
c d e c                | %2
e-2 f g2               | %3
e4 f g2                | %4
g8-4\( a-5 g f\) e4 c  | %5
g'8\( a g f\) e4 c     | %6
c-1 r c2               | %7
c4 r c2                | %8

Использование awkдля чтения файла дважды, один раз для определения максимальной длины строки(m)и еще раз для форматирования строк до этой длины. columnздесь не используется (или в последнем решении):

$ awk 'FNR==NR { m=(length>m?length:m); next } { printf("%-*s | %%%d\n", m, $0, FNR) }' file file
c4-1 d e c            | %1
c d e c               | %2
e-2 f g2              | %3
e4 f g2               | %4
g8-4\( a-5 g f\) e4 c | %5
g'8\( a g f\) e4 c    | %6
c-1 r c2              | %7
c4 r c2               | %8

Обратите внимание, что имя файла вводится дважды в командной строке.


То же, что и выше, но файл сохраняется в памяти как массив(a)и печатается в соответствии с самой длинной строкой в ​​конце. Доступ к диску помогает уменьшить потребление памяти :

.
$ awk '{ a[FNR]=$0; m=(length>m?length:m) } END { for (i=1; i<=FNR; ++i) printf("%-*s | %%%d\n", m, a[i], i) }' file
c4-1 d e c            | %1
c d e c               | %2
e-2 f g2              | %3
e4 f g2               | %4
g8-4\( a-5 g f\) e4 c | %5
g'8\( a g f\) e4 c    | %6
c-1 r c2              | %7
c4 r c2               | %8
2
27.01.2020, 20:04

Теги

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