Bash - assign array into variable as string

11,456

Solution 1

When IFS='-' read -r -a host_name_array <<< "$(hostname)" is ran, the array is (tech news blog 324344).

After the final element is removed with unset 'host_name_array[${#host_name_array[@]}-1]', the array is (tech news blog).

So, to get this to echo tech-news-blog, some substitution will have to be done, since echo "${host_name_array[*]}" will yield tech news blog:

With tr: echo "${host_name_array[*]}" | tr ' ' '-'

sed: echo "${host_name_array[*]}" | sed 's/ /-/g'

Solution 2

You could do this by outputting the elements separated by -, and then strip off the last - by parameter expansion:

$ var=$(printf '%s-' "${host_name_array[@]}")

$ echo "$var"
foo-bar-spam-egg-

$ var="${var%-}"

$ echo "$var"
foo-bar-spam-egg

Also you need ${host_name_array[@]} instead of ${host_name_array[*]} to prevent outputting the elements as a whole separated by first character of IFS.


What you are trying to do can be achieved by a simple parameter expansion:

${var%-*}

Example:

$ var=$(hostname)

$ echo "${var%-*}"

Solution 3

(...) introduces a subshell. So $URL wouldn't be set after that (still have the value it had before the subshell). You want:

IFS=-
read -r -a host_name_array <<< "$(hostname)" 
unset 'host_name_array[${#host_name_array[@]}-1]'
URL="${host_name_array[*]}"

"${host_name_array[*]}" joins the elements on the arrays on the first character of $IFS just like "$*" does in standard sh.

If the reason why you're using a subshell is because you don't want to modify $IFS globally, you could do that in a function where you give $IFS a local scope:

f() {
  local IFS=-
  ...
}
f

Or use command substitution that also creates a subshell but allows passing data to the parent shell:

URL=$(IFS=-; printf '%s\n' "${host_name_array[*]}")

Here though I'd use standard sh expansion to remove that trailing component:

URL=$(uname -n) # uname -n is the standard equivalent of hostname
URL=${URL%-*}

It has several advantages over the above:

  • it works even if the text contains newline characters (very unlikely for host names here though);
  • if the text doesn't contain -, it doesn't remove anything;
  • it is more efficient. read <<< $(hostname) means running hostname, read its output through a pipe, storing that in a temp file and have read read the first line of that;
  • it doesn't clobber the variable namespace with those temporary variables
  • it is shorter;
  • it is portable. No need to install bash to run that code. The system's sh will suffice.

In any case, remember to quote your variables when using them in list contexts:

printf '%s\n' "$URL"

When doing:

echo $URL

You're invoking the split+glob operator. So, if $IFS still contains -, that $URL would be split on -, and echo would output those words separated by spaces.

Share:
11,456

Related videos on Youtube

BenB
Author by

BenB

Updated on September 18, 2022

Comments

  • BenB
    BenB over 1 year

    I have this code, it prints the correct result, but I can't figure out how to get the echo from the last line into a variable.

    # hostname is 'tech-news-blog-324344' . Setting it into array host_name_array
    IFS='-' read -r -a host_name_array <<< "$(hostname)" 
    #removing the last part of string after last "-"
    unset 'host_name_array[${#host_name_array[@]}-1]'
    ( IFS=$'-'; echo "${host_name_array[*]}" )  
    #result is 'tech-news-blog'
    

    How could get the value of the last line into a variable? I've tried the following:

    ( IFS=$'-'; URL="${host_name_array[*]}" )
    

    But I get the result "tech news blog" with spaces between pieces of array instead of '-'.

  • BenB
    BenB over 7 years
    Both the echo works, but if I try to set that result into a variable and reuse it I get from the variable the string with spaces
  • Kenneth B. Jensen
    Kenneth B. Jensen over 7 years
    var=$(echo "${host_name_array[*]}" | tr ' ' '-'), but I think @heemayl's solution is better, since it is much less bulky and awkward.
  • BenB
    BenB over 7 years
    When I echo the $var I get the string with spaces for some reason
  • BenB
    BenB over 7 years
    About his answer, I have the same issue there when I echo the $var I get the string with spaces
  • Kenneth B. Jensen
    Kenneth B. Jensen over 7 years
    Is IFS still set to '-'? If so, that may be the cause; reset it with unset IFS.
  • F. Hauri
    F. Hauri over 7 years
    Wow, this is strong! Why did you not use printf -v var "%s-" ... syntax?
  • F. Hauri
    F. Hauri over 7 years
    @heemayl Using var=$(printf... implie one fork to subshell, where printf -v ... let you use builtin printf and set var without forks! This is a lot quicker.
  • heemayl
    heemayl over 7 years
    @F.Hauri I was serious there :) You are absolutely right :)