1

I am trying to run commands based on the output of a previous command:

ifaces=$(ls /sys/class/net)
for i in "${ifaces[@]}"
do
   mac=$(cat /sys/class/net/$i/address)
   echo "$i: $mac"
done

but its not working, i'm not sure if my method of concatenation is wrong?

0

2 Answers 2

2
for i in /sys/class/net/*; do
  mac=$(<"$i/address")
  echo "${i##*/}: $mac"
done
  • ls output is formatted for human readability rather than progammatic use. Because filenames can contain literal newlines, but ls separates names with newlines, it's impossible to both literally represent those names (without escape characters or sequences) and distinguish where on name ends and the next begins. Don't use it programatically.
  • $(<file), unlike $(cat "$file"), doesn't actually need to fork() off a subprocess, or exec() an external executable. Consequently, it's considerably more efficient.
  • ${i##*/} removes the longest string matching the glob expression */ to the variable $i. Consequently, it effectively returns only the filename.
Sign up to request clarification or add additional context in comments.

Comments

0

When your assigning the output of ls to ifaces, wrap it with an array to successfully iterate over the contents:

ifaces=($(ls /sys/class/net))
for i in "${ifaces[@]}"
do
   mac=$(cat /sys/class/net/$i/address)
   echo "$i: $mac"
done

3 Comments

Yes, an array is the right thing. No, it shouldn't be populated from ls.
Duly noted, sir.
See BashPitfalls #1 as a reference.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.