Извлечь значение времени работы из вывода команды "w"

Как я могу получить значение up снизу команда на linux?

# w
 01:16:08 up 20:29,  1 user,  load average: 0.50, 0.34, 0.30
USER     TTY        LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0     00:57    0.00s  0.11s  0.02s w

# w | grep up
 01:16:17 up 20:29,  1 user,  load average: 0.42, 0.33, 0.29

3 ответа

Решение

Учитывая, что формат времени безотказной работы зависит от того, меньше ли он или больше, чем 24 часа, лучшее, что я могу придумать, - это двойное awk:

$ w
 18:35:23 up 18 days, 9:08, 6 users,...
$ w | awk -F 'user|up ' 'NF > 1 {print $2}' \
    | awk -F ','       '{for(i = 1; i < NF; i++) {printf("%s ",$i)}} END{print ""}'
18 days   9:08

В Linux самый простой способ получить время безотказной работы в (дробных) секундах - через 1-е поле /proc/uptime (увидеть man proc):

$ cut -d ' ' -f1 /proc/uptime
350735.47

Чтобы отформатировать это число так же, как w а также uptime делать, используя awk:

$ awk '{s=int($1);d=int(s/86400);h=int(s % 86400/3600);m=int(s % 3600 / 60);
       printf "%d days, %02d:%02d\n", d, h, m}' /proc/uptime
4 days, 01:25   # 4 days, 1 hour, and 25 minutes

Чтобы ответить на вопрос как задано - разбор выходных w (или uptime чей вывод такой же, как w 1-я строка вывода, которая содержит всю интересующую информацию), которая также работает в macOS / BSD, с гранулярностью целых секунд:

perl решение:

<(uptime) это замена процесса Bash, которая обеспечивает uptime в качестве входных данных для perl Команда - см. снизу.

$ perl -nle 'print for / up +((?:\d+ days?, +)?[^,]+)/' <(uptime)
4 days, 01:25

Это предполагает, что days самая большая единица, отображаемая каждый.

  • perl -nle говорит Perl обрабатывать ввод построчно, не выводя вывод по умолчанию (-n), автоматически удаляя завершающий символ новой строки из каждой входной строки на входе и автоматически добавляя один на выходе (-l); -e говорит Perl обрабатывать следующий аргумент как скрипт (выражение) для обработки.

  • print for /.../ говорит Perl выводить то, что каждая группа захвата (...) внутри регулярное выражение /.../ захватывает.

    • up + соответствует буквальному up с предшествующим (как минимум) одним пробелом, за которым следуют 1 или более пробелов (+)
    • (?:\d+ days?, +)? является невыражающим подвыражением - из-за ?: - что соответствует:

      • 1 или более цифр (\d+)
      • с последующим пробелом
      • с последующим буквальным day, за которым может следовать буквальный s (s?)
      • отставание ? делает все подвыражение необязательным, учитывая, что часть количества дней может присутствовать или не присутствовать.
    • [^,]+ соответствует 1 или более (+) последующие символы до, но не включая буквальный , ([^,]) - это hh:mm часть.

    • Общая группа захвата - внешняя (...) поэтому захватывает все выражение времени работы - будь то в составе hh:mm только или перед <n> day/s> - и печатает это.

  • <(uptime) является заменой процесса Bash ( <(...) ) что, собственно говоря, дарит uptime выводится как (временный, самоуничтожающийся) файл, который perl можно читать через стандартный ввод.

Примерно так с gnu sed:

$ w |head -n1
 02:06:19 up  3:42,  1 user,  load average: 0.01, 0.05, 0.13

$ w |sed -r '1 s/.*up *(.*),.*user.*/\1/g;q'
3:42

$ echo "18:35:23 up 18 days, 9:08, 6 users,  load average: 0.09, 0.31, 0.41" \
|sed -r '1 s/.*up *(.*),.*user.*/\1/g;q'
18 days, 9:08
Другие вопросы по тегам