Я хочу получить строку из вывода команды, но одновременно удалить подстроку. Например
Строка = Активен: активен (работает) с сб 2022-03-12 20:02:20 PKT; 1ч 31мин назад
Чего я хочу = активен (работает) с 20:02:20 PKT
Удаленный
Для этого я изначально использовал регулярное выражение
sudo service sshd status |grep -Po '(?<=Active: )(.*) since (.*);'
active (running) since Mon 2022-03-14 01:06:43 PKT;
Можете ли вы сказать, как я могу игнорировать дату, а также последнюю точку с запятой; сохраняя только время и выводя точно так же, как:
active (running) since 01:06:43 PKT
Спасибо
Полный вывод команды:
● xrdp.service - xrdp daemon
Loaded: loaded (/lib/systemd/system/xrdp.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2022-03-14 01:06:44 PKT; 3 days ago
Docs: man:xrdp(8)
man:xrdp.ini(5)
Process: 668 ExecStartPre=/bin/sh /usr/share/xrdp/socksetup (code=exited, status=0/SUCCESS)
Process: 682 ExecStart=/usr/sbin/xrdp $XRDP_OPTIONS (code=exited, status=0/SUCCESS)
Main PID: 687 (xrdp)
Tasks: 1 (limit: 4915)
CGroup: /system.slice/xrdp.service
└─687 /usr/sbin/xrdp
systemd[1]: Starting xrdp daemon...
xrdp[682]: (682)(-1224841088)[DEBUG] Testing if xrdp can listen on 0.0.0.0 port 3389.
xrdp[682]: (682)(-1224841088)[DEBUG] Closed socket 7 (AF_INET6 :: port 3389)
systemd[1]: xrdp.service: Can't open PID file /run/xrdp/xrdp.pid (yet?) after start: No such file or directory```
Ты можешь использовать
sed -nE 's/^ *Active: +(.* since ).*([0-9]{2}:[0-9]{2}:[0-9]{2}[^;]*).*/\1\2/p'
Подробности:
-nE
- n
подавляет вывод строки по умолчанию, а E
включает синтаксис регулярных выражений POSIX ERE.^Active: +(.* since ).*([0-9]{2}:[0-9]{2}:[0-9]{2}[^;]*).*
- находит совпадающие строки
^ *Active: +
- начало строки, ноль или более пробелов, Active:
и один или более пробелов(.* since )
- Группа 1 (\1
): любой текст и затем пробел + since
+ пробел.*
- любой текст([0-9]{2}:[0-9]{2}:[0-9]{2}[^;]*)
- две цифры, :
, две цифры, :
, две цифры, а затем любой ноль или более символов, кроме ;
.*
- остальная часть строки\1\2
- объединенные значения группы 1 и 2p
- p
выводит результат замены.См. онлайн демо:
#!/bin/bash
s=' Active: active (running) since Sat 2022-03-12 20:02:20 PKT; 1h 31min ago'
sed -nE 's/^ *Active: +(.* since ).*([0-9]{2}:[0-9]{2}:[0-9]{2}[^;]*).*/\1\2/p' <<< "$s"
Выход:
active (running) since 20:02:20 PKT
Как ни странно, когда строка хранится в переменной, она дает правильный вывод. При использовании с командой это не работает. sudo service xrdp status | sed -nE 's/^Active: +(.* since ).*([0-9]{2}:[0-9]{2}:[0-9]{2}[^;]*).*/\1\2/p'
Не выдает вывода, хотя та же строка содержится в многострочном выводе команды. Я добавил полный вывод рассматриваемой команды для справки.
@BilalBhatti Потому что в начале строки есть пробелы. Я добавил ' *'
после ^
в регулярном выражении, и теперь это работает.
Спасибо. Иногда вывод выглядит так: Как мы можем иметь одно регулярное выражение для обработки обоих?
@BilalBhatti И что тогда? Это ожидается? Что такое вход? Попробуйте sed -nE 's/^ *Active: +(.* since ).*([0-9]{2}:[0-9]{2}:[0-9]{2}[^;]*).*|.*(Active: inactive \(dead\)).*/\1\2\3/p'
С показанными образцами попробуйте следовать коду awk
. Написано и протестировано в GNU awk
. Простым объяснением было бы создание переменной оболочки с именем val
и отправка ее значения в awk
, а затем в программе awk
я использую функцию match
для сопоставления с регулярным выражением для получения требуемого значения.
val = "Active: active (running) since Sat 2022-03-12 20:02:20 PKT; 1h 31min ago"
echo "$val" |
awk '
match($0,/^Active:[[:space:]]+active \(running\)[[:space:]]+.*[0-9]{4}(-[0-9]{2}){2}[[:space:]]+([0-9]{2}:){2}[0-9]{2}[^;]*/){
val=substr($0,RSTART,RLENGTH)
sub(/^Active:[[:space:]]+/,"",val)
sub(/since[[:space:]]+\S+\s+\S+/,"since",val)
print val
}
'
Объяснение регулярного выражения:
^Active:[[:space:]]+ ##Matching value starting from Active: followed by space(s).
active \(running\) ##matching active followed by a space followed by (running).
[[:space:]]+.*[0-9]{4} ##Matching 1 or more spaces then using greedy match to match 4 occurrences of digits.
(-[0-9]{2}){2} ##Matching - followed by 2 digits and this whole combination 2 times.
[[:space:]]+([0-9]{2}:){2} ##Matching space(s) followed by 2 digits followed by colon and this whole combination 2 times.
[0-9]{2}[^;]* ##Matching 2 digits and everything after it till a semi-colon comes.
Вы можете удалить точку с запятой с помощью
grep -Po '(?<=Active: )(.*) since (.*)(?=;)'
, но для даты в середине шаблона вы достигли ограничений GNU grep, поэтому вам придется добавить что-то вроде| sed 's/since [^ ]* [^ ]*/since/'
к команде