コマンド出力で空白を含む要素で配列を初期化する方法

コマンド出力で空白を含む要素で配列を初期化する方法

次のスクリプト:

DYN_HOSTS_START_ARRAY=($(grep -E "STARTING HOST" sample.log | cut -d' ' -f 1,2))
for ((i=0; i< ${#DYN_HOSTS_START_ARRAY[@]}; i++))
do
    echo "$i:  start: "${DYN_HOSTS_START_ARRAY[$i]}""
done

次のサンプル .log ファイルを使用します。

2019-11-11 19:05:55,823 DEBUG  STARTING HOST 46
2019-11-11 19:05:55,831 DEBUG  STARTING HOST 703
2019-11-11 19:05:55,837 DEBUG  STARTING HOST 505
2019-11-11 19:05:55,858 DEBUG  STARTING HOST 93
2019-11-11 19:05:55,859 DEBUG  STARTING HOST 486
2019-11-11 19:05:55,861 DEBUG  STARTING HOST 72
2019-11-11 19:05:55,879 DEBUG STARTING HOST 855
2019-11-11 19:05:55,913 DEBUG  STARTING HOST 560
2019-11-11 19:05:56,067 DEBUG STARTING HOST 199

次のような不要な出力が生成されます。

0:  start: 2019-11-11
1:  start: 19:05:55,823
2:  start: 2019-11-11
3:  start: 19:05:55,831
4:  start: 2019-11-11
5:  start: 19:05:55,837
6:  start: 2019-11-11
7:  start: 19:05:55,858
8:  start: 2019-11-11
9:  start: 19:05:55,859
10:  start: 2019-11-11
11:  start: 19:05:55,861
12:  start: 2019-11-11
13:  start: 19:05:55,879
14:  start: 2019-11-11
15:  start: 19:05:55,913
16:  start: 2019-11-11
17:  start: 19:05:56,067

必要な出力には18個ではなく9個の要素のみを含める必要があり、各要素には生の空白で区切られた日時が含まれます。

アレイの初期化を維持しながらスクリプトを変更するにはどうすればよいですか?たった9つの要素、これを達成するには?

答え1

mapfile -t次のように、プロセス置換でデータを使用して読み取ることができます。@クサラナンダ指摘した。

mapfile -t dyn_hosts_start_array < <(grep 'STARTING HOST' sample.log | cut -d' ' -f 1,2)    
for i in "${!dyn_hosts_start_array[@]}"; do
  printf '%s:  start: %s\n' "$i" "${dyn_hosts_start_array[i]}"
done

または、IFS単語の区切りに使用される変数を改行文字(デフォルトはスペース、タブ、および改行文字)に変更してから、元の値に戻すこともできます。

oldifs=$IFS
IFS=$'\n'
dyn_hosts_start_array=( $(grep 'STARTING HOST' sample.log | cut -d' ' -f 1,2) )
IFS=$oldifs    
for i in "${!dyn_hosts_start_array[@]}"; do
  printf '%s:  start: %s\n' "$i" "${dyn_hosts_start_array[i]}"
done

出力(2つのバリエーション):

0:  start: 2019-11-11 19:05:55,823
1:  start: 2019-11-11 19:05:55,831
2:  start: 2019-11-11 19:05:55,837
3:  start: 2019-11-11 19:05:55,858
4:  start: 2019-11-11 19:05:55,859
5:  start: 2019-11-11 19:05:55,861
6:  start: 2019-11-11 19:05:55,879
7:  start: 2019-11-11 19:05:55,913
8:  start: 2019-11-11 19:05:56,067

関連:

答え2

awk '{print NR-1 ": ", "start:", $1, $2;}' sample.log

質問に印刷された入力を使用してください。

0:  start: 2019-11-11 19:05:55,823
1:  start: 2019-11-11 19:05:55,831
2:  start: 2019-11-11 19:05:55,837
3:  start: 2019-11-11 19:05:55,858
4:  start: 2019-11-11 19:05:55,859
5:  start: 2019-11-11 19:05:55,861
6:  start: 2019-11-11 19:05:55,879
7:  start: 2019-11-11 19:05:55,913
8:  start: 2019-11-11 19:05:56,067

出力形式をより効果的に制御するには、次のものを使用することもprintfできます。

awk '{printf "%d:  start: %s %s\n", NR-1, $1, $2;}' sample.log

コマンドの置き換えには、スペースや特殊文字がある場合はいくつかの欠点があります。明らかに、入力の2つのフィールドは別々の配列要素に保持される。このスクリプトは、元のスクリプトに基づいてそれらを結合します。

DYN_HOSTS_START_ARRAY=($(grep -E "STARTING HOST" sample.log | cut -d' ' -f 1,2))
for ((i=0; i< ((${#DYN_HOSTS_START_ARRAY[@]} / 2)); i++))
do
    echo "$i:  start: ${DYN_HOSTS_START_ARRAY[((2 * $i))]} ${DYN_HOSTS_START_ARRAY[((2 * $i + 1))]}"
done

関連情報