7
\$\begingroup\$

On Linux, the file /proc/cpuinfo returns a set of key-value pairs, where the key and value are separated by a colon and each pair has its own line. It's a bit more complicated than that in reality, but for my needs that's as complicated as it needs to be. (I have only one processor core.)

My goal is to write a function in bash that takes the key for one of those items and returns the value corresponding to that key. Here's my current function:

function get_cpuinfo_prop () {
    TARGET_LINE=$(cat /proc/cpuinfo | grep ^$1)
    IFS=':'
    read -ra PARTS <<< "$TARGET_LINE"
    PROP_VALUE=${PARTS[1]}
    echo $PROP_VALUE
}

And you'd call it like this:

$(get_cpuinfo_prop 'key_name')

Is there a better way of doing it? How could I improve this code? Additionally, I think this might be returning extra whitespace before the actual value. How can I trim those characters off the beginning/end?

\$\endgroup\$
4
  • \$\begingroup\$ What if you have more than one processor or core, as is common these days? \$\endgroup\$ Commented Jan 12, 2016 at 5:29
  • \$\begingroup\$ On the platform that this script is running on, the values that I need are not repeated for each core (and there is only one core anyway). That's what I was trying to say with that complication note; should I add this info explicitly to the question? \$\endgroup\$
    – Wasabi Fan
    Commented Jan 12, 2016 at 5:34
  • \$\begingroup\$ I think you have a bug in here. Sometimes one key can be a subset of another key. For instance, if you are looking for the key "model" this will also find the line "model name". \$\endgroup\$ Commented Jan 15 at 7:53
  • \$\begingroup\$ To fix the issue with the key subsets, you can use grep -e -m1 "$1\s*:" The \s means, whitespace but no characters, * means, an unlimited number, and : ends the pattern at the : in the line you are looking for. \$\endgroup\$ Commented Jan 15 at 8:05

1 Answer 1

8
\$\begingroup\$

Useless use of cat

Grep can open files all by itself, cat isn't necessary in most circumstances. Also, quote everything - that's save you some debugging when you need to handle spaces in them - like for the "model name" property.

target_line=$(grep -m1 ^"$1" /proc/cpuinfo)

-m1 to stop at the first match, so you won't get weird results when you run your script on a machine with more CPUs. That's not portable unfortunately (not in POSIX), so if you don't have that, the usual options are: pipe to head -n 1, use awk instead and exit early, sed and exit early. The latter two can do it all in one go too.

Use your shells string manipulations for simple things

Assuming you want everything after the :, you can simply do:

value="${target_line##*: }"

See How do I do string manipulations in bash? for more like this, or the POSIX parameter expansion reference.

function keyword not necessary

It's less portable and doesn't buy you anything, so just omit it. See difference between “function foo() {}” and “foo() {}” for more details.

Variable names don't need to be in all caps

Personal preference of course, but especially for locals, lowercase is good - keep uppercase for globals/environment variables.

So:

get_cpuinfo_prop () {
  target_line=$(grep -m1 ^"$1" /proc/cpuinfo)
  echo "${target_line##*: }"
}
\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.