По сути, вы хотите создать двумерный массив значений. Первый столбец в каждой строке соответствует ключу , взятому из первого поля, разделенного табуляцией, в каждой строке каждого входного файла. Каждый следующий столбец соответствует отдельному входному файлу.
awk 'BEGIN {
RS = "(\r\n|\n\r|\r|\n)"
FS = " *\t *"
SUBSEP = ":"
}
FNR==1 {
++file
}
NF>=2 {
if ($1 in keynum)
key = keynum[$1]
else {
key = ++keys
keynum[$1] = key
keystr[key] = $1
}
value[key,file] = $2
}
END {
files = file
for (key = 1; key <= keys; key++) {
printf "%s", keystr[key]
for (file = 1; file <= files; file++)
printf "\t%s", value[key,file]
printf "\n"
}
}' INPUT1 INPUT2 ... INPUTN
Правило BEGIN
устанавливает в качестве разделителя записей любой тип новой строки, так что каждая строка является отдельной записью. Он также устанавливает разделитель полей на табуляцию, включая любые пробелы вокруг нее.
В awk все массивы ассоциативны и в основном одномерны.Многомерные массивы поддерживаются путем объединения индексов с подпунктом SUBSEP
между ними. Здесь мы используем :
в качестве разделителя, потому что используемые индексы являются положительными целыми числами. (При желании вы можете использовать множество других символов; например, табуляцию \ t
.)
Правило FNR == 1
запускается в первой строке каждого входного файла. Мы увеличиваем переменную файл
так, чтобы она составляла 1
для первого входного файла, 2
для второго и так далее.
Правило NF> = 2
срабатывает для всех записей как минимум с двумя полями. В данном случае это означает, что для каждой строки есть символ табуляции. Первое поле - это ключ , а второе поле - значение .
Переменная key
является положительным целым числом, относящимся к уникальной строке ключа. (1 относится к первому уникальному ключу , 2 - ко второму и т. Д., Во всех входных файлах.)
Ассоциативный массив keynum
сопоставляет строки ключей с номерами ключей ( ключ
, положительные целые числа). keystr
- это обратное отображение, отображающее номера ключей в строки ключей.
В правиле NF> = 2
, если первое поле уже является известным ключом, ищется его номер. В противном случае первое поле добавляется как новая уникальная строка ключа. Затем второе поле сохраняется в массиве значение
.
Правило END
срабатывает после обработки всех входных файлов.Массив value
, логически двумерный массив, содержит нужные нам поля.
Внешний цикл перебирает ключ
по всем обнаруженным уникальным ключам в том порядке, в котором они были впервые обнаружены. Каждая итерация внешнего цикла создает одну строку вывода.
Внутренний цикл перебирает файл
по каждому входному файлу в том порядке, в котором они были перечислены. Каждая итерация создает дополнительный столбец к текущей строке вывода. Каждая строка вывода содержит ровно на один столбец больше, чем указанное количество входных файлов. (Обратите внимание, что если входные файлы не указаны, awk читает со стандартного ввода, и это считается, как если бы это был один входной файл.)
Это определенно не самый простой способ добиться этого, но мне он нравится, потому что он надежный (принимает входные файлы, созданные в Unix, Linux, старых Mac, новых Mac, Windows - в основном везде, где используется ASCII-совместимый набор символов; кроме того, он не запутается, если некоторые входные файлы имеют только подмножество всех известные ключи), относительно легко понять, поддерживать и адаптировать к подобным случаям.
Если вы хотите запустить вышеуказанное как сценарий, сохраните следующее, например, paste.awk
:
#!/usr/bin/awk -f
BEGIN {
RS = "(\r\n|\n\r|\r|\n)"
FS = " *\t *"
SUBSEP = ":"
}
FNR==1 {
++file
}
NF>=2 {
if ($1 in keynum)
key = keynum[$1]
else {
key = ++keys
keynum[$1] = key
keystr[key] = $1
}
printf "key = %s, file = %s, value = %s\n", key, file, $2 >/dev/stderr
value[key,file] = $2
}
END {
files = file
for (key = 1; key <= keys; key++) {
printf "%s", keystr[key]
for (file = 1; file <= files; file++)
printf "\t%s", value[key,file]
printf "\n"
}
}
Если у вас есть input1
, содержащий
a
A 5
C 4
D 2
и input2
, содержащий
b
A 2
B 5
C 3
и input3
, содержащий
c
B 4
C 4
D 2
], но со вторым символом в каждой строке Tab ; т.е. создано с использованием, например,
printf ' \ta\nA\t5\nC\t4\nD\t2\n' > input1
printf ' \tb\nA\t2\nB\t5\nC\t3\n' > input2
printf ' \tc\nB\t4\nC\t4\nD\t2\n' > input3
или, если вы скопируете и вставите текст выше в файлы, запустите sed -e 's | ^ \ (.\) * | \ 1 \ t | ' -i input1 input2 input3
, чтобы исправить их; затем выполнение
paste.awk input1 input2 input3
выводит
a b c
A 5 2
C 4 3 4
D 2 2
B 5 4
, за исключением того, что следующие подряд пробелы на самом деле являются вкладками . Как видите, программное обеспечение на этом сайте преобразует табуляции в пробелы.
Отредактировано для добавления: если вы хотите использовать какое-то предопределенное значение для отсутствующих записей,измените правило END
на
END {
files = file
for (key = 1; key <= keys; key++) {
printf "%s", keystr[key]
for (file = 1; file <= files; file++)
if ((key SUBSEP file) in value)
printf "\t%s", value[key,file]
else
printf "\t%s", blank
printf "\n"
}
}
и установите переменную пустой
, чтобы отразить желаемое значение. (Вы можете установить его из командной строки, используя ./ paste.awk -v blank = 0 input1 input2 input3
, либо изменить код awk и установить значение где-нибудь в BEGIN
] или начало правила END
.)
/lib/systemd/system/hwclock -save.service
[root@hostname username]# more /lib/systemd/system/hwclock-save.service
[Unit]
Description=Synchronise Hardware Clock to System Clock
DefaultDependencies=no
Before=shutdown.target
ConditionFileIsExecutable=!/usr/sbin/ntpd
ConditionFileIsExecutable=!/usr/sbin/openntpd
ConditionFileIsExecutable=!/usr/sbin/chrony
ConditionVirtualization=!container
[Service]
Type=oneshot
ExecStart=/sbin/hwclock -D --systohc
[Install]
WantedBy=reboot.target halt.target poweroff.target
Таким образом, в конечном итоге он вызывает/sbin/hwclock