web-dev-qa-db-ja.com

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[*]}" )

しかし、「-」の代わりに配列の各要素の間にスペースが含まれる「tech news blog」という結果が表示されます。

3
BenB

IFS='-' read -r -a Host_name_array <<< "$(hostname)"が実行されると、配列は(tech news blog 324344)になります。

最後の要素がunset 'Host_name_array[${#Host_name_array[@]}-1]'で削除された後、配列は(tech news blog)になります。

したがって、これをtech-news-blogにエコーするには、echo "${Host_name_array[*]}"tech news blogを生成するため、いくつかの置換を行う必要があります。

Trの場合:echo "${Host_name_array[*]}" | tr ' ' '-'

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

3

これを行うには、-で区切られた要素を出力し、最後の-をパラメーター展開によって取り除きます。

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

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

$ var="${var%-}"

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

また、IFSの最初の文字で区切られた要素全体を出力しないようにするには、${Host_name_array[@]}ではなく${Host_name_array[*]}が必要です。


あなたがやろうとしていることは、単純なパラメーター拡張によって実現できます:

${var%-*}

例:

$ var=$(hostname)

$ echo "${var%-*}"
3
heemayl

_(...)_はサブシェルを導入します。したがって、_$URL_はその後は設定されません(サブシェルの前の値のままです)。あなたが欲しい:

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

_"${Host_name_array[*]}"_は、標準のshの_$IFS_と同様に、_"$*"_の最初の文字で配列の要素を結合します。

サブシェルを使用する理由が_$IFS_をグローバルに変更したくない場合は、_$IFS_にローカルスコープを指定する関数でそれを行うことができます。

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

または、サブシェルも作成するが、データを親シェルに渡すことができるコマンド置換を使用します。

_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はスペースで区切られた単語を出力します。

2

bash 特定の答え:whipeforks

これはすでに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"
0
F. Hauri