1

How can I get the value of up from below command on 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
mklement0
  • 382,024
  • 64
  • 607
  • 775

3 Answers3

4

On Linux, the easiest way to get the uptime in (fractional) seconds is via the 1st field of /proc/uptime (see man proc):

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

To format that number the same way that w and uptime do, using 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

To answer the question as asked - parsing the output of w (or uptime, whose output is the same as w's 1st output line, which contains all the information of interest), which also works on macOS/BSD, with a granularity of integral seconds:

A perl solution:

<(uptime) is a Bash process substitution that provides uptime's output as input to the perl command - see bottom.

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

This assumes that days is the largest unit every displayed.

  • perl -nle tells Perl to process the input line by line, without printing any output by default (-n), automatically stripping the trailing newline from each input line on input, and automatically appending one on output (-l); -e tells Perl to treat the next argument as the script (expression) to process.

  • print for /.../ tells Perl to output what each capture group (...) inside regex /.../ captures.

    • up + matches literal up, preceded by (at least) one space and followed by 1 or more spaces (+)
    • (?:\d+ days?, +)? is a non-capturing subexpression - due to ?: - that matches:

      • 1 or more digits (\d+)
      • followed by a single space
      • followed by literal day, optionally followed by a literal s (s?)
      • the trailing ? makes the entire subexpression optional, given that a number-of-days part may or may not be present.
    • [^,]+ matches 1 or more (+) subsequent characters up to, but not including a literal , ([^,]) - this is the hh:mm part.

    • The overall capture group - the outer (...) therefore captures the entire up-time expression - whether composed of hh:mm only, or preceded by <n> day/s> - and prints that.

  • <(uptime) is a Bash process substitution (<(...)) that, loosely speaking, presents uptime's output as a (temporary, self-deleting) file that perl can read via stdin.

mklement0
  • 382,024
  • 64
  • 607
  • 775
2

Something like this with 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
George Vasiliou
  • 6,130
  • 2
  • 20
  • 27
0

Given that the format of the uptime depends on whether it is less or more than 24 hours, the best I could come up with is a double 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
DYZ
  • 55,249
  • 10
  • 64
  • 93
  • 1
    @Sweety It would be simpler to use the `/proc/uptime` method described in another answer. – Barmar May 04 '17 at 14:40