Regexp/grep to find one of two identical values, depending on a heading?

I have this output on the command line:

% pmset -g custom
Battery Power:
 lidwake              1
 lowpowermode         1
 standbydelayhigh     86400
 standbydelaylow      10800
 standby              1
 proximitywake        0
 ttyskeepawake        1
 hibernatemode        3
 powernap             0
 gpuswitch            2
 hibernatefile        /var/vm/sleepimage
 highstandbythreshold 50
 displaysleep         2
 womp                 0
 networkoversleep     0
 sleep                1
 lessbright           1
 halfdim              1
 tcpkeepalive         1
 acwake               0
 disksleep            10
AC Power:
 lidwake              1
 lowpowermode         0
 standbydelayhigh     86400
 standbydelaylow      0
 standby              1
 proximitywake        1
 ttyskeepawake        1
 hibernatemode        3
 powernap             0
 gpuswitch            2
 hibernatefile        /var/vm/sleepimage
 highstandbythreshold 50
 displaysleep         5
 womp                 1
 networkoversleep     0
 sleep                1
 tcpkeepalive         1
 halfdim              1
 acwake               0
 disksleep            10

As you can see there are two copies of most entries, the only difference being the “headings” (Battery Power vs AC Power). The order of both the entries and the headings is not guaranteed. I want a robust way to find the value for displaysleep. That is, I want to specify Battery Power or AC Power and then get the displaysleep value for that section. Is there a better way than to “not break at linefeed” “non-greedy match”? Something like a hierarchical notation (pseudo code) “get AC ‘Power.displaysleep'” à la XML, Java objects etc?

7

If you don’t mind combining awk with column, then it’s really straight forward without needing to store any amount of data in arrays

pmset -g custom | 

awk '/^((AC|Battery) Power[:]$|[ t]+displaysleep[ t])/ && 
     (ORS = ORS < FS ? FS : RS)' | 

column -t

Output:

Battery  Power:  displaysleep  2
AC       Power:  displaysleep  5

From here, filtering AC Power vs. Battery Power is trivial.

2

Using awk:

function get_displaysleep_from_power () {
    pmset -g custom | awk -v heading="$1" '
    BEGIN {heading_found=0}
    {
        if(!heading_found){
            heading_found=match($1,"^"heading)
        }
        if (heading_found){
            if ($1 == "displaysleep") {
                print $2;
                exit
            }
        }
    }
    ' - 
}

get_displaysleep_from_power "AC"
get_displaysleep_from_power "Battery"

outputs:

5
2

I would harness GNU AWK for this task following way, let command output be

Battery Power:
 lidwake              1
 lowpowermode         1
 standbydelayhigh     86400
 standbydelaylow      10800
 standby              1
 proximitywake        0
 ttyskeepawake        1
 hibernatemode        3
 powernap             0
 gpuswitch            2
 hibernatefile        /var/vm/sleepimage
 highstandbythreshold 50
 displaysleep         2
 womp                 0
 networkoversleep     0
 sleep                1
 lessbright           1
 halfdim              1
 tcpkeepalive         1
 acwake               0
 disksleep            10
AC Power:
 lidwake              1
 lowpowermode         0
 standbydelayhigh     86400
 standbydelaylow      0
 standby              1
 proximitywake        1
 ttyskeepawake        1
 hibernatemode        3
 powernap             0
 gpuswitch            2
 hibernatefile        /var/vm/sleepimage
 highstandbythreshold 50
 displaysleep         5
 womp                 1
 networkoversleep     0
 sleep                1
 tcpkeepalive         1
 halfdim              1
 acwake               0
 disksleep            10

then

command | awk '/^[A-Z]/{head=$1;next}{arr[head][$1]=$2}END{print arr["AC"]["displaysleep"]}'

gives output

5

Explanation: for lines starting with uppercase letter I set head value to 1st field (Battery and AC for given data) and instruct GNU AWK to go next line that is not doing anything more. For all others lines I set value in 2D array under head-1st field key. In END I print value under desired key.

(tested in GNU Awk 5.1.0)

If you are looking for a robust way to create a hierarchical data structure from what you see output from pmset there are several ways:

  1. Use awk in paragraph mode to easily catch the header and the time of interest;
  2. Use a regex to parse all the output and build a hash from that;
  3. Use the Apple tools to parse the binary plist file.

Here is a simple awk to get the value of displaysleep for all sections:

x=$(pmset -g custom | sed -E 's/([^[:blank:]][^:]*:)/nn1/') 
echo "$x" | awk 'BEGIN{RS=""; FS="n"} {
      for(i=1;i<=NF;i++) if ($i~"^ displaysleep ") 
          print $1, $i
}'  

Prints:

Battery Power:  displaysleep         2
AC Power:  displaysleep         10

The problem with parsing the output from pmset -g custom is that the spaces may be ambiguous. Examples:

  • Both keys and values can have spaces and one or more spaces are used to delimit between key and value.

  • The value for the key "hibernatefile" is potentially a file with a space in it.

  • The key "sleep" not only reports status but may report the reason the actual state is different than assigned. If I enter pmset -g | grep ' sleep ' the return is sleep 0 (sleep prevented by bluetoothd, coreaudiod, powerd, sharingd)

With those provisos, you can parse the output of pmset with the knowledge that some values for certain keys cannot be reliably parsed without further knowledge of that specific key.

Here is a Ruby that will parse the output of pmset -g custom into a Ruby hash. That hash can then be queried as a two level hash (["Battery Power"]["powermode"]) or turned into a structure like JSON to query in another way:

pmset -g custom | ruby -r json -e '
    dat=$<.read.scan(/^(S+s+Power:[sS]+?(?=(?:^S+s+Power:$)|z))/).
    map{|a| sa=a[0].split(/:s*R[ t]+/,2); [sa[0], sa[1].split(/R[  t]+/)]}.
    map{|sa| 
        [sa[0], sa[1].flatten.map{|s| s.scan(/^([^n]+?)s+(S+$)/)}.
        flatten(1).to_h] }.
    to_h

#output that hash
puts "pmset -g custom as hash:n#{dat}nn"

puts ""Battery Power"."powermode": #{dat["Battery Power"]["powermode"]}nn"

puts "pmset -g custom as JSON:n#{JSON.pretty_generate(dat)}"'

Prints:

pmset -g custom as hash:
{"Battery Power"=>{"Sleep On Power Button"=>"1", "powermode"=>"0", "standby"=>"1", "ttyskeepawake"=>"1", "hibernatemode"=>"3", "powernap"=>"1", "hibernatefile"=>"/var/vm/sleepimage", "displaysleep"=>"2", "womp"=>"0", "networkoversleep"=>"0", "sleep"=>"1", "lessbright"=>"1", "tcpkeepalive"=>"1", "disksleep"=>"0"}, "AC Power"=>{"Sleep On Power Button"=>"1", "powermode"=>"0", "standby"=>"1", "ttyskeepawake"=>"1", "hibernatemode"=>"3", "powernap"=>"1", "hibernatefile"=>"/var/vm/sleepimage", "displaysleep"=>"10", "womp"=>"1", "networkoversleep"=>"0", "sleep"=>"0", "tcpkeepalive"=>"1", "disksleep"=>"0"}}

"Battery Power"."powermode": 0

pmset -g custom as JSON:
{
  "Battery Power": {
    "Sleep On Power Button": "1",
    "powermode": "0",
    "standby": "1",
    "ttyskeepawake": "1",
    "hibernatemode": "3",
    "powernap": "1",
    "hibernatefile": "/var/vm/sleepimage",
    "displaysleep": "2",
    "womp": "0",
    "networkoversleep": "0",
    "sleep": "1",
    "lessbright": "1",
    "tcpkeepalive": "1",
    "disksleep": "0"
  },
  "AC Power": {
    "Sleep On Power Button": "1",
    "powermode": "0",
    "standby": "1",
    "ttyskeepawake": "1",
    "hibernatemode": "3",
    "powernap": "1",
    "hibernatefile": "/var/vm/sleepimage",
    "displaysleep": "10",
    "womp": "1",
    "networkoversleep": "0",
    "sleep": "0",
    "tcpkeepalive": "1",
    "disksleep": "0"
  }
}

Alternatively, you can do it the proper Apple Way which is to reference the actual plist file.

Here is a Ruby that parses the plist file into XML:

ruby -e '

# Depending on the version of OS X, the plist can be at 
# /Library/Preferences/SystemConfiguration/com.apple.PowerManagement.plist
info_plist=File.read("/Library/Preferences/com.apple.PowerManagement.plist")

puts IO.popen("plutil -convert xml1 -r -o - -- -", "r+") {|f|
  f.write(info_plist)
  f.close_write
  info_plist = f.read # xml plist
}'

Prints:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>AC Power</key>
    <dict>
        <key>DarkWakeBackgroundTasks</key>
        <integer>1</integer>
        <key>Disk Sleep Timer</key>
        <integer>0</integer>
        <key>Display Sleep Timer</key>
        <integer>10</integer>
        <key>System Sleep Timer</key>
        <integer>0</integer>
        <key>Wake On LAN</key>
        <integer>1</integer>
    </dict>
    <key>Battery Power</key>
    <dict>
        <key>DarkWakeBackgroundTasks</key>
        <integer>1</integer>
        <key>Disk Sleep Timer</key>
        <integer>0</integer>
        <key>Display Sleep Timer</key>
        <integer>2</integer>
        <key>ReduceBrightness</key>
        <integer>1</integer>
        <key>System Sleep Timer</key>
        <integer>1</integer>
        <key>Wake On LAN</key>
        <integer>0</integer>
    </dict>
    <key>SystemPowerSettings</key>
    <dict>
        <key>Update DarkWakeBG Setting</key>
        <true/>
    </dict>
</dict>
</plist>

You can then query that XML file.

This might work for you (GNU sed and bash):

 f(){ p=${1:-Battery};
      pmset -g custom | sed -En '/:$/h;G;s/ (displaysleep.*)n('$p'.*)/2 1/p'; }

Create a shell function that sends the output of the pmset command through sed and outputs by default Battery Power or AC Power if supplied with the parameter AC.

I wouldn’t normally answer a question that doesn’t contain an attempt by the OP to solve their own problem but since there are multiple answers already:

Using any awk:

$ pmset -g custom | awk -v pwr='Battery' -v tag='displaysleep' 'index($0,pwr" ")==1{p=1} p && $1==tag{print $2; exit}'
2

Assuming the headings don’t appear anywhere else and aren’t repeated, your question amounts to:

  • skip over stuff until
  • either of the headings is matched
  • skip over more stuff until
  • displaysleep is matched

And doing that twice

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật