Рассмотрим следующий сценарий awk, duplicates.awk
:
#!/usr/bin/awk -f
BEGIN {
RS = "(\r\n|\n\r|\r|\n)"
FS = "[\t\v\f ]*;[\t\v\f ]*"
split("", count)
}
{
count[$3]++
}
END {
for (item in count) {
if (count[item] > 1)
printf "%s\n", item
}
}
Не забудьте сделать его исполняемым, используя, например, chmod a + rx duplicates.awk
. Вы можете передать входные данные команде по конвейеру или передать один или несколько входных файлов в качестве параметров командной строки (несколько файлов обрабатываются так, как если бы они были объединены в один файл).
Правило BEGIN устанавливает универсальные символы новой строки (то есть принимает все соглашения о новой строке от MS-DOS до старых Mac и Unix) и точки с запятой ;
в качестве разделителя полей.Для иллюстрации я сделал так, чтобы разделитель полей также занимал все окружающие его пробелы, так что x; foo bar; y
разбирается на три поля: x
, foo bar
и y
.
Правило записи (средняя часть фрагмента) применяется к каждой записи (строке) во входных данных. Поскольку awk поддерживает ассоциативные массивы, мы просто используем третье поле, строку, как ключ к массиву count
, и увеличиваем эту запись на единицу. (Увеличение несуществующей записи массива в awk дает 1, поэтому первое приращение дает 1, и код работает так, как и следовало ожидать.)
Правило END сканирует массив count
, распечатывая записи, которые произошло как минимум дважды. Обратите внимание, что этот вывод находится в случайном порядке. (Есть способы отсортировать вывод по количеству вхождений или даже сохранить исходный порядок (первых вхождений) в файле, но OP не упомянул никаких требований относительно упорядочения, поэтому я не беспокоился; undefined порядок является самым простым для реализации.)
Если вы хотите напечатать, например, количество вхождений, за которыми следует строка (значение из третьего столбца), затем используйте вместо этого следующее правило END:
END {
for (item in count)
printf "%15d %s\n", count[item], item
}
Вывод форматируется так, что первые пятнадцать символов вывода зарезервированы для числа, а значение начинается с 17-го символа.
Вот некоторые незначительные изменения:
network.target
. nohup
не требуется, поскольку systemd
демонизирует исполняемый файл за вас. dev / null
и т. Д.) Не требуется, поскольку systemd устанавливает соответствующий стандартный контекст ввода-вывода. В самом деле, если вы уберете перенаправление из , systemd будет записывать все, что отправлено на стандартный вывод программой Java в своем журнале, без специального механизма ведения журнала. &
) не требуется и не подходит. Type = forking
требуется особый шаблон поведения, и если демон не будет следовать ему, все пойдет не так. Поэтому попробуйте ввести Type = simple
(или Type = notify
). Итак, служебный файл выглядит так:
[Unit]
Description=Some job
After=network.target
[Service]
WorkingDirectory=/home/user/tmp/testout
SyslogIdentifier=SocketTest
ExecStart=/bin/sh -c "exec java -jar /home/user/programming/tests/java/core/SocketTest/SocketTest.jar"
User=dlt
Type=simple
[Install]
WantedBy=multi-user.target
Примечания:
java
в качестве имени запускаемой программы. systemd не выполняет поиск исполняемых файлов в PATH
, и имя исполняемого файла, присвоенное ExecStart
, должно быть абсолютным. Поэтому, если вам нужен поиск по пути, вы должны вызвать его через оболочку или / usr / bin / env
. Здесь мы выбираем / bin / sh
. Type = simple
, оболочка должна exec
Java, а не запускать ее как дочерний процесс.systemd управляет службой через основной процесс, и это должен быть Java, а не процесс родительской оболочки. sh
в свой журнал в качестве имени службы. См. Как избежать отметки / usr / bin / env в журналах systemd как исполняемый файл для получения дополнительной информации. Насколько мне известно, нет никаких особых предостережений относительно запуска Java-приложений с Systemd.