0

I need to place the output of a command in Bash into a string variable.

Each value should be separated by a space. There are many options to do that but I cannot use mapfileor read options (I'm using Bash < 4 version in macOS).

This is the output of the command:

values="$(mycommand | awk 'NR > 2 { printf "%s\n", $2 }')"

where mycommand is just a cloud command that gets some values like:

echo $values

mycommand output: (which I think is a string ending with \n for each value)

55369972
75369973
85369974
95369975

This is what I'm trying to do:

Here I should print the values like (I need to iterate over the variable values so I can print each value individually).

desired output in the foor loop

value: 55369972
value: 75369973
value: 85369974
value: 95369975

but I'm getting this:

value: 55369972 75369973 85369974 95369975

# Getting the id field of the values
values="$(mycommand| awk 'NR > 2 { printf "%s\n", $2 }')"
# Replacing the new line with a space so I can iterate over each value
new_values="${values//$'\n'/ }"
# new_values=("${values//$'\n'/ }")
# Checking if I can print each value correctly
for i in "${new_values[@]}"
# for i in "$new_values"
do
  echo "value: ${i}"
done

Also, I cannot use things like

# shellcheck disable=xxx
values=($(echo "${values}" | tr "\n" " "))

As I'm getting error messages when checking the code...

Any idea what I'm doing wrong in my code?

X T
  • 445
  • 6
  • 22
  • The variable `new_values` computed as `new_values="${values//$'\n'/ }"` is a string, not an array. It makes no sense to iterate on its presumed elements. – Pierre François Jan 12 '23 at 09:07
  • Since we don't have access to your command `mycommand`, you could simplify your question by initializing in your sample of code the variable `values` to the string `55369972 75369973...` (with blanks or newlines as separators). – Pierre François Jan 12 '23 at 09:12
  • `printf "value: %i\n" $values` or `echo "$values" | sed 's/^/value: /'` – tripleee Jan 12 '23 at 09:26

3 Answers3

1

try this:

#!/bin/bash

values="$(mycommand | awk 'NR > 2 { printf "%s\n", $2 }')"
for v in $values; do
  echo value: $v
done
akathimi
  • 1,393
  • 11
  • In my case it's not working since the output is a string with ('\n' at the end of each field). I tried your code but getting `value: 55369972 55369978 55369975` – X T Jan 12 '23 at 09:33
  • 1
    can you please try adding `IFS=' '` before the for loop ? – akathimi Jan 12 '23 at 09:39
  • Same output even adding `IFS=' '` before the loop. I'm using the shell `zhs` in macOS. I'm not sure if that's the issue here. – X T Jan 12 '23 at 09:46
  • since you have the bash shebang it shouldn't matter, can you please share the actual command of "mycommand"? – akathimi Jan 12 '23 at 09:49
  • The command is just a cloud command that gets some values. For example, `az xxx all-values` and the output is like the one I posted. – X T Jan 12 '23 at 09:58
  • what happens if you just modify the awk to print the "value", the command would be: `values="$(mycommand | awk 'NR > 2 { printf "value %s\n", $2 }')"` then just `echo $values` – akathimi Jan 12 '23 at 10:17
  • I'm getting `value value01` under `value value02` under `value value03` – X T Jan 12 '23 at 10:20
  • isnt that what is required ? – akathimi Jan 12 '23 at 10:22
  • No, it's not. I need to place the output in a string (or a list) separated by space so later I can iterate over each value in the for loop and print the value ``value: value01` value: value02`. I can't iterate like I want with you code. – X T Jan 12 '23 at 10:25
  • I think you need to change the way your are retrieving the data from azure. for example: `IFS=$'\n' regions=($(az account list-locations --query "[].name" -o tsv)) for region in "${regions[@]}"; do echo "$region" done` – akathimi Jan 12 '23 at 10:52
0

Since I can't paste code into the comments, I post an answer but the credits go to @akathimy above.

This works for me (solution #1):

#!/bin/bash
# Getting the id field of the values
values="55369972 75369973 85369974 95369975"
# 
for v in $values; do
  echo value: "$v"
done

and this also (solution #2):

#!/bin/bash
# Getting the id field of the values
values="55369972
75369973
85369974
95369975"
# 
for v in $values; do
  echo value: "$v"
done

Edit: And what about this one (solution #3)? :

#!/bin/bash
# Getting the id field of the values
values=("55369972
75369973
85369974
95369975")
# 
for v in ${values[@]}; do
  echo value: "$v"
done

This last one works for me, and perhaps also for you. Let me know.

Pierre François
  • 5,850
  • 1
  • 17
  • 38
  • In my case it's not working since the output is a string with ('\n' at the end of each field). I tried your code but getting value: 55369972 55369978 55369975 – X T Jan 12 '23 at 09:33
  • @Shefferdock: You mean the second version of my code above doesn't work? In my environment, it does. I see your OS is MacOS. Shall this make a difference? – Pierre François Jan 12 '23 at 11:53
  • the second version of your code does not cinlude '\n' at the end of each value, right? Each value in my output is ending with \n I think. – X T Jan 12 '23 at 12:04
  • @Shefferdock: the code above (solution #2) introduces a new line into the string at the moment of the initialization. As you can see, the assignment `value="..."` splits over several lines, isn't it? – Pierre François Jan 12 '23 at 12:08
  • Youy are right. However, the output of my command is doing something strange as it's not working the same way than your code. Is there any way to check if the values of what I'm putting in the variable have new lines at the end of each value? – X T Jan 12 '23 at 12:09
  • @Shefferdock: redirect the output of your command to a file (with the operator `>`) and see which chars are used at the end of the lines with some utility like `od`. – Pierre François Jan 12 '23 at 12:12
0

Your step that replaces the newlines with spaces renders it as a string. If you want to split that string into a list, you should put it in brackets (based on this answer )

This should do what you are expecting:

# Getting the id field of the values
values="$(mycommand| awk 'NR > 2 { printf "%s\n", $2 }')"
# Replacing the new line with a space
new_values=("${values//$'\n'/ }")
# Checking if I can print the values correctly
for i in ${new_values}
do
  echo "value: ${i}"
done

where new_values=("${values//$'\n'/ }") is the crucial part, then you need to avoid putting it in quotes when you iterate it (or you turn it back into a string)

Stephen
  • 31
  • 2
  • I'm trying your code but still getting the wrong output `value: value01 value02 value03...`. I think the output of my command is a string with '\n' at the end of the values (correct me if I'm wrong). If I print the `new_values` when I replace the `\n` with a `space` and place the values into a list I get (value01 value02 value03...) which seems correct but in the `for loop`I'm still getting `value_value01 value02 value03 ...` – X T Jan 12 '23 at 09:41
  • I tested the code with: values="1 2 3 5" as a replacement for your input, and it worked. Can I check that your for loop is `for i in ${new_values}` without any quotation marks? – Stephen Jan 13 '23 at 00:19
  • sorry, `values=$'1\n2\n3\n5'` even (markdown wont let me write newlines in comments) – Stephen Jan 13 '23 at 00:25