Bash - 将数组作为字符串分配给变量

Bash - 将数组作为字符串分配给变量

我有这段代码,它打印了正确的结果,但我不知道如何将最后一行的回显获取到变量中。

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

如何将最后一行的值放入变量中?我尝试过以下方法:

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

但我得到的结果是“科技新闻博客”,数组之间有空格而不是“-”。

答案1

运行时IFS='-' read -r -a host_name_array <<< "$(hostname)",数组为(tech news blog 324344)

用 删除最后一个元素后 unset 'host_name_array[${#host_name_array[@]}-1]',数组为(tech news blog)

因此,为了得到 echo tech-news-blog,必须进行一些替换,因为 echo "${host_name_array[*]}"将产生tech news blog

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

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

答案2

您可以通过输出由 分隔的元素来完成此操作,然后通过参数扩展-去掉最后一个元素:-

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

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

$ var="${var%-}"

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

此外,您还需要${host_name_array[@]}防止${host_name_array[*]}将元素作为一个整体输出,并用 的第一个字符分隔IFS


您想要做的事情可以通过简单的参数扩展来实现:

${var%-*}

例子:

$ var=$(hostname)

$ echo "${var%-*}"

答案3

(...)引入一个子shell。所以$URL在那之后不会被设置(仍然具有子 shell 之前的值)。你要:

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

"${host_name_array[*]}"$IFS就像"$*"在 standard 中一样,将数组中的元素连接到第一个字符上sh

如果您使用子 shell 的原因是因为您不想$IFS全局修改,则可以在给出$IFS本地作用域的函数中执行此操作:

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

或者使用命令替换来创建子 shell,但允许将数据传递到父 shell:

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

不过,在这里我将使用标准sh扩展来删除该尾随组件:

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

与上述相比,它有几个优点:

  • 即使文本包含换行符它也能工作(尽管这里的主机名不太可能);
  • 如果文本不包含-,则不会删除任何内容;
  • 它更有效率。read <<< $(hostname)意味着运行hostname,通过管道读取其输出,将其存储在临时文件中并读取read该文件的第一行;
  • 它不会用这些临时变量破坏变量名称空间
  • 它更短;
  • 它是便携式的。无需安装bash即可运行该代码。系统sh就够了。

任何状况之下,记得引用你的变量在列表上下文中使用它们时:

printf '%s\n' "$URL"

做时:

回显$URL

您正在调用 split+glob 运算符。因此,如果$IFS仍然包含-$URL则会在 上拆分-,并echo输出用空格分隔的单词。

答案4

具体答案:鞭子叉子

由于这已经使用了 bashisms,sedtr任何其他外部工具都是无用的:

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// /-}

或者更简单:

这更短、更快、更简单:

read myvar < <(hostname)
echo ${myvar%-*}

如果您确实host_name_array出于其他原因需要:

read shorted < <(hostname)
host_name_array=(${shorted//-/ })
shorted=${shorted%-*}

所以你有一个数组简短的主机名:

declare -p host_name_array shorted

将返回类似以下内容:

declare -a host_name_array='([0]="tech" [1]="news" [2]="blog" [3]="324344")'
declare -- shorted="tech-news-blog"

相关内容