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 '-'.

share|improve this question
up vote 2 down vote accepted

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'

share|improve this answer
    
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 – batz yesterday
    
var=$(echo "${host_name_array[*]}" | tr ' ' '-'), but I think @heemayl's solution is better, since it is much less bulky and awkward. – Kenneth B. Jensen yesterday
    
When I echo the $var I get the string with spaces for some reason – batz yesterday
1  
Is IFS still set to '-'? If so, that may be the cause; reset it with unset IFS. – Kenneth B. Jensen yesterday
1  
Using echo with tr/sed is silly here. "${array[*]}" does join the elements on the first character of IFS. Here you're joining with spaces and converting all spaces to dashes instead of just joining with dash in the first place. – Stéphane Chazelas 22 hours ago

(...) 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|improve this answer

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%-*}"
share|improve this answer
    
The echo outputs correctly, but if I try to put into a variable and use the variable, I get the string with spaces "tech news blog". How could I set the string "tech-blog-news" into a variable and re-use it? – batz yesterday
    
Wow, this is strong! Why did you not use printf -v var "%s-" ... syntax? – F. Hauri 23 hours ago
    
@F.Hauri You know what, thanks for reminding me; i always tend to forget that :) – heemayl 22 hours ago

specific answer

As this already use bashisms, sed, tr or any other external tool are useless:

IFS='-' read -r -a host_name_array < <(hostname)
#removing the last part of string after last "-"
unset host_name_array[${#host_name_array[@]}-1]

shorted=${host_name_array[*]}
echo ${shorted// /-}

Or simplier:

read myvar < <(hostname)
echo ${myvar%-*}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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