0

Edit #3: My question has been closed and marked as duplicate which I am unable to follow. I posted here because I was asking for help :(

enter image description here

I'm familiar with doing this type of thing in batch but can't work out how to do it in ash (edit: ash not bash). I'm searching an openwrt configuration file /etc/config/wireless for wifi-iface settings.

So far I can get the required output:

root@OpenWrt:~# awk '/wifi-iface/ {print $3}' /etc/config/wireless | sed s/\'//g
default_radio0
default_radio1
wifinet1

My question is how can I turn this output into variables like using a for f loop?

Edit #1: Something like:

root@OpenWrt:~# echo $a
default_radio0

root@OpenWrt:~# echo $b
default_radio1

root@OpenWrt:~# echo $c
wifinet1

Edit #2: I'm guessing i need to change the output from lines to string:

root@OpenWrt:~# awk '/wifi-iface/ {print $3}' /etc/config/wireless | sed s/\'//g
 | xargs
default_radio0 default_radio1 wifinet1

Getting closer but then how does the for loop work?

Brenton
  • 35
  • 11

3 Answers3

1

You can capture the output of a command into a variable using the $(command) construct:

wireless_list=$(awk '/wifi-iface/ {print $3}' /etc/config/wireless | sed s/\'//g)
for w in ${wireless_list} ; do
    # Do something with $w
    echo "$w"
done

Alternative approach, using array (which will be safer to evaluate):

readarray -t wireless_list <<< "$(awk '/wifi-iface/ {print $3}' /etc/config/wireless | sed s/\'//g)"
for w in "${wireless_list[@]}" ; do
    # Do something with $w
    echo "$w"
done
dash-o
  • 13,723
  • 1
  • 10
  • 37
  • Thanks. I'm still very unfamiliar with this. Your first example `echo $w` shows nothing and the second example errors on readarray `line 4: syntax error: unexpected redirection` the `readarray` command isn't available by default with this shell `readarray: not found` – Brenton Sep 12 '20 at 06:38
  • 1
    @Brenton you did not specify what should be done in side the 'for' loop. I've modified the code to print the variable. The error message for 'readarray' indicate that you are not using 'bash' - check if the script is invoked as 'sh' - which will disable bash features. – dash-o Sep 12 '20 at 06:47
  • My test script is bash `#!/bin/sh` OpenWrt has very minimal busybox. Your first script works but the output is a single variable. I've also edited my post to better describe what I need to do. I'm trying to print the output to use it as a choice option (eg: `$a $b $c`) Thanks for your help @dash-o – Brenton Sep 12 '20 at 07:21
  • 1
    @brenton `with this shell readarray: not found` Then please remove `bash` tag, and add tag for appriopriate shell. If you tag `bash`, ppl will assume you want a bash solution. The first code snippet should certainly work for you, what do you mean by "but the output is a single variable"? – KamilCuk Sep 12 '20 at 08:55
  • 1
    Then you do want to "turn this output into variables like using a for f loop?" or you want to "set three variables $a $b $c"? – KamilCuk Sep 12 '20 at 09:56
  • @KamilCuk thanks I wasn't aware there was a difference between bash and ash? I'm using OpenWrt linux kernel 4.14.180 BusyBox v1.30.1 () built-in shell (ash). Scripts are headed with #!/bin/sh, Please advise what is the correct tag to use... And "but the output is a single variable"? means the echo "$w" from @dash-o is the same as the original output. I am trying to create three variables `$a $b $c` – Brenton Sep 12 '20 at 10:01
  • @KamilCuk I want to learn how to "turn this output into variables like using a for f loop?" so I can count them and assign them. Also print them as user input choices. So for example if greater than 1 then ask user to choose a b or c... or 1 2 or 3. – Brenton Sep 12 '20 at 10:05
  • Without a main page to view because someone decided to close my question I don't think I can learn anything from comments in this small print. Thanks for being helpful. – Brenton Sep 12 '20 at 10:08
1

turn this output into variables like using a for f loop?

Then the first snippet from the other answer is enough.

how to set multiple line output to variables

In general, save the whole output somewhere. From there, extract lines, one at a time, and assign to variables, if you wish. A more shell-ish way would to parse the data in a pipeline as they go without storing it anywhere.

I am trying to set three variables $a $b $c

A good POSIX way with a temporary file and a read:

tmpf=$(mktemp)
awk '/wifi-iface/ {print $3}' /etc/config/wireless | sed s/\'//g > "$tmpf"
{
   # read three lines of input
    IFS= read -r a
    IFS= read -r b
    IFS= read -r c
} < "$tmpf"
rm "$tmpf"

But without a temporary file, you can invoke three processes to extract the lines:

tmp=$(awk '/wifi-iface/ {print $3}' /etc/config/wireless | sed s/\'//g)
a=$(printf "%s\n" "$tmp" | sed '1!d')
b=$(printf "%s\n" "$tmp" | sed '2!d')
c=$(printf "%s\n" "$tmp" | sed '3!d')

or maybe a bit clearer with tab separated content:

tmp=$(awk '/wifi-iface/ {print $3}' /etc/config/wireless | sed s/\'//g | paste -s)
a=$(printf "%s\n" "$tmp" | cut -f1)
b=$(printf "%s\n" "$tmp" | cut -f2)
c=$(printf "%s\n" "$tmp" | cut -f3)

I'm guessing i need to change the output from lines to string:

Lines are strings.

is there a way to read all lines 1 to x?

Just don't remove lines from specific range.

x=50; 
... | sed "1,$x!d"
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Thanks @KamilCut for unlocking my post and this gives me a clear idea of how it works thanks so much. Rather than set 3 fixed lines is there a way to read all lines 1 to x? – Brenton Sep 12 '20 at 12:28
  • 1
    I believe, you'll want to become familiar with standard unix tools like `paste` `cut` and `xargs` and read a good introduction into `sed`. I see little sense in reading data into 3 separate named differently variables, because the solution scales badly and for me it serves here only as a educational exercise. [Here is a sed introduction that shows how to apply command on range of lines](https://www.grymoire.com/Unix/Sed.html#uh-46) – KamilCuk Sep 12 '20 at 12:49
  • `paste` is not available in my shell but the other examples work great. I can't get anything to work bash or ash in the linked "duplicate" post. `my_array=()` errors and the `mapfile`, `declare` and `element` functions are also unavailable... – Brenton Sep 12 '20 at 13:11
  • "I see little sense in reading data into 3 separate named differently variables" yes exactly. The data will change and not always be 3. This is why I need a line count. I'm assuming you are directing me to learn more about `sed` for this purpose. Thanks for your help :) – Brenton Sep 12 '20 at 13:21
  • 1
    `my_array=() errors` _bash_ arrays are bash extension `the mapfile, declare` are bash extensions, not available in posix shell. [this link seems nice](https://unix.stackexchange.com/questions/555099/how-to-write-the-most-portable-shell-scripts) `why I need a line count` Use `wc -l` to count lines – KamilCuk Sep 13 '20 at 07:21
  • "Use wc -l to count lines" yes I've implemented wc for the input `if [[ $userinput -gt $count ]] then echo "invalid"` but I still can't figure out how to create dynamic variables, in my example the options would be `var1=default_radio0 var2=default_radio1 var3=wifinet1`. I can't figure out how your example `x=50; ... | sed "1,$x!d"` is implemented. It seems a bit complicated using sh not bash :( – Brenton Sep 13 '20 at 07:59
  • 1
    As I said, don't. Such method doesn't scale well. Parse data in a pipeline as they go. On another side, there are definitely resources available on the net on how to emulate an array in a posix shell. So if you request to use an array anyway, write a proper abstraction. And this looks like an XY problem. – KamilCuk Sep 13 '20 at 08:09
  • @KamilCut thanks for the guidance. Good news emulated array and count `((++n))` is working now I'm up to [here](https://stackoverflow.com/questions/16854280/a-variable-modified-inside-a-while-loop-is-not-remembered) ... `line 6: var1=default_radio0: not found` ... `line 6: var2=default_radio1: not found` ... `line 6: var3=wifinet1: not found` :) – Brenton Sep 13 '20 at 09:18
0

Thanks for your help @dash-o and @KamilCuk I finally managed to figure out what to do:

#!/bin/sh

function list_wifi {
wifi=$(awk '/wifi-iface/ {print $3}' /etc/config/wireless | sed s/\'//g)

count=0 && for string in $wifi
  do
    eval ap$((++count))=$string
  done

ap=$(echo "$wifi" | wc -l)
  if [[ $ap -eq 1 ]];
    then
      echo next_function
    else
      echo "--Multiple APs detected"
  fi

count=0 && for string in $wifi
  do
    echo $((++count))-$string
  done

x=0 && while [[ $x -lt 1 || $x -gt $ap ]]
  do
    printf "--Select AP to clone (1-$ap): "
    read x
  done
}

Results in:

root@OpenWrt:~# sh test
--Multiple APs detected
1-default_radio0
2-default_radio1
3-wifinet1
--Select AP to clone (1-3):

With variables:

echo $ap1
default_radio0
echo $ap2
default_radio1
echo $ap3
wifinet1
Brenton
  • 35
  • 11