2

I'm learning bash from a book and just wanted to see if there is a more efficient way to do this.

The output of cat /proc/acpi/wakeup is multiple lines, but I only care about this one:

GPP0      S4    *disabled  pci:0000:00:01.1

So I can grep for just that line no problem, but I only need the value under the Status column, that is, I only need to know whether its value is enabled or disabled.

This part of my script is conditional. If the user tries to Suspend the system, and the status is set to disabled, it should go ahead and Suspend. Otherwise, if the status is enabled, it should disable it first before allowing the system to Suspend.

I have come up with three different approaches to this:

First approach (using cut):

cat /proc/acpi/wakeup | grep GPP0 | cut -d "*" -f 2 | cut -d " " -f 1    # 'disabled'

Second appraoch (using awk):

cat /proc/acpi/wakeup | grep GPP0 | awk '{print $3}' | cut -d "*" -f 2

Third approach:

cat /proc/acpi/wakeup | grep GPP0 | awk '{if ($3 == "*disabled") print "Already disabled"; else print "DISABLE IT"}'

I'm leaning toward the third approach, but I was wondering if there is a standard way to grab the value from the Status column. For example using GPP0 as the "key" and enabled or disabled would be the "value."

I could not find this in the manpages or tldr tool.

Also, I realize that the choice to use cat could be the problem with the script's efficiency, so if there is a better tool that is standard for grabbing values of keys, please let me know.

8
  • 3
    Try awk '$1=="GPP0" {print $3}' /proc/acpi/wakeup (avoiding cat and grep altogether) or awk '$1=="GPP0" {print substr($3,2)}' /proc/acpi/wakeup (to also cut off the first character). Commented Sep 8 at 19:20
  • 3
    why not simply: if grep -q "GPP0.*disabled" /proc/acpi/wakeup; then echo already disapled; else echo ask 4 disabling,..;fi Commented Sep 8 at 19:20
  • 2
    Keep reading your book. cat <file> | grep <pattern> | awk <program> can be shortened to just one command: awk '/<pattern>/ <program>' <file> ;) . Commented Sep 8 at 19:46
  • 2
    in the general case, your logic is insufficient, since it misses the case where there is no line at all starting GPU0. So it should be a tristate test, not boolean. However, if "not present" should have the same behaviour as one of "enabled" or "disabled", then, either grep -q 'GPU0.*disabled' /proc/acpi/wakeup (succeeds if disabled, fails if not present or enabled) or ! grep -q 'GPU0.*enabled' /proc/acpi/wakeup (suceeds if not present or disabled, fails if enabled) could be used Commented Sep 9 at 4:56
  • 1
    (also assumes that the value can only be *enabled or *disabled) Commented Sep 9 at 5:03

4 Answers 4

8

There are few standard ways to do anything in shell programming. There are almost always multiple ways to do it, with equivalent performance and maintenance cost.

Here's a solution that is a little more concise:

awk '$1 == "GPP0" && $3 == "*disabled" { print "Disabled" }' /proc/acpi/wakeup

Awk can do many things that grep and cat can do (and other tools like cut and sed), including reading directly from a file instead of stdin.

It's particularly awk-ish to use the pattern { action } syntax instead of using if in the action block.

Sign up to request clarification or add additional context in comments.

Comments

3

Assuming your input looks like this (other lines borrowed from https://askubuntu.com/questions/152403/how-do-i-make-changes-to-proc-acpi-wakeup-permanent):

$ cat file
Device  S-state   Status   Sysfs node
SMB0      S4    *disabled  pci:0000:00:03.2
PBB0      S4    *disabled  pci:0000:00:09.0
GPP0      S4    *disabled  pci:0000:00:01.1
HDAC      S4    *disabled  pci:0000:00:08.0
PWRB      S4    *enabled
SLPB      S4    *enabled

and you just want to be able to test if the Status is enabled so you can disable it then this is probably what you want so you can test for success/fail in an "if":

awk -v dev='GPP0' '$1==dev{exit ($3 ~ /disabled/)}' file

e.g.:

if awk -v dev='GPP0' '$1==dev{exit ($3 ~ /disabled/)}' file; then
    echo '>>> Disable it'
fi
echo '>>> Suspend it'
>>> Suspend it

if awk -v dev='PWRB' '$1==dev{exit ($3 ~ /disabled/)}' file; then
    echo '>>> Disable it'
fi
echo '>>> Suspend it'
>>> Disable it
>>> Suspend it

Comments

1

I don't know the general format of the input data, but perhaps a simple

if ! grep -q 'GPP0.*disabled'  /proc/acpi/wakeup 
then
  echo GPP0 is disabled
fi

would be sufficient.

The negation copes for the case that there is no line at all for GPP0.

1 Comment

Or grep -Pq '^GPP0\s+\S+\s+\*disabled' to be equivalent to the OP.
0

Building on user1934428's excellent answer, here is a more generic solution that caters for a greater variation in input lines. Using all ideas here is likely to be overkill for this use case, but they do illustrate the power of grep.

key=GPP0 grep -oPm 1 "^$key\s+\S+\s+\*\K[[:alpha:]]+abled\b" /proc/acpi/wakeup || echo disabled

Explanation:

  • -o print only the matching parts of the matched lines

  • -P use Perl regular expressions

  • -m 1 print the first match only (and exit without scanning the rest of the file)

  • ^ match start of line

  • \s+ match one or more whitespace characters

  • \S+ match one or more non-whitespace characters

  • \* match a literal *

  • \K when printing, discard the portion of the matched part until this point

  • [[:alpha:]]+ match one or more alphabetic characters

  • \b match edge of word (here, transition from non-whitespace to whitespace)

  • || statement to execute if grep produces no output (i.e. fails to find a match)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.