使用bash将每个第n个元素从更大的数组添加到数组中

时间:2015-04-14 06:49:49

标签: bash

我有一个小问题,我有一个看起来像这样的数组,我从输入文件读取它(cols由制表符分隔)

1   1   1   1   1
9   3   4   5   5
6   7   8   9   7
3   6   8   9   1
3   4   2   1   4
6   4   4   7   7

a=[1 1 1 1 1 9 3 4 5 5 6 7 8 9 7 3 6 8 9 1 3 4 2 1 4 6 4 4 7 7]

现在我正在尝试编写一个代码,它应该以这种方式提供输出(组合每个第6个元素并形成一个数组并打印出来:

1 9 6 3 3 6
1 3 7 6 4 4
1 4 8 8 2 4
1 5 9 9 1 7
1 5 7 1 4 7

我是bash的新手并尝试编写此代码(iter = no of cols-1):

for ((i=0; i< $iter;i++))
      do
      for ((j=i; j< ${#a[@]}; j+$cols))
          do
          echo "${a[j]}"
          done
      done

我已编写此代码,但它将进入无限循环。怎么解决这个问题。有没有更简单的方法呢?这是我的整个脚本:

#! /bin/bash
clear
declare -i rem= 1
if [ "$#" -eq 0 ]; then
    echo "Please provide arguments"
elif [ "$#" -lt 2 ]; then
     echo "You have to provide 2 arguments"
elif [ "$#" -gt 2 ]; then
    echo "You have provided more number of arguments"
else
    echo "You have entered correct number of arguments"
fi
option="${1}" 
case ${option} in 
   -rows| -r) FILE="${2}"
      echo "rows" 
      echo "File name is $FILE"
      clear
      echo "Average Median"
      while read -r line
      do
      len=0
      tot=0
      name=$line
      IFS="    " read -a array <<< "$name"
      for element in "${array[@]}"
      do
          tot=$(expr $tot + $element)
          #let tot+=$element #you can use this as well to get the totals
          let len+=1
      done
      avg= printf "%.0f" $(echo "scale=2;$tot/$len" | bc)
      readarray -t sorted < <(for a in "${array[@]}"; do echo "$a"; done | sort)
      no=`expr $len % 2`
      if [ $no -eq 0 ]; then
      mid=`expr $len / 2`
      echo "$avg   ${sorted[$mid]}"
      else
      mid=`expr $len / 2`
      echo "$avg   ${sorted[$mid]}"
      fi
      unset "array[@]"
      unset "sorted[@]"
      done < "$FILE"
      ;;

   -cols| -c) FILE="${2}" 
      echo "cols"
      echo "File name is $FILE"
      cols=$(head -1 "$FILE" | tr "\t" '\n' | wc -l)
      lines=$(wc -l < "$FILE")
      iter=`expr $cols - $rem`
      echo $iter
      echo $cols
      echo $lines
      readarray a < "$FILE"
      echo ${a[@]}

      while read line;do
      x=1
      read -a array <<< "$line" ##Split the line by spaces
      for element in "${!array[@]}"
      do
      row[${element}]=$((${row[${element}]}+${array[$element]})) ##For each column increment array variable by number in the column.
      ((x++))
      done
      done < "$FILE"

      for element in ${row[@]}
      do
      mean= printf "%.0f" $(echo "scale=2;$element/$x" | bc) ##bc prints floating point numbers and then we round of using scale and .0f
      echo -n "$mean    "
      done
      printf "\n"

      ;; 
   *)  
      echo "`basename ${0}`:usage: [-r|-rows rows] | [-c|-cols columns]" 
      exit 1 # Command to come out of the program with status 1
      ;; 
esac 

可以这样运行:

./stats.sh -rows test_file or ./stat.sh -cols test_file

2 个答案:

答案 0 :(得分:1)

#!/usr/bin/env bash
rows=6 # number of rows of the original matrix
cols=5 # number of columns of the original matrix
a=(1 1 1 1 1 9 3 4 5 5 6 7 8 9 7 3 6 8 9 1 3 4 2 1 4 6 4 4 7 7) # bash array is wrapped in parentheses
for ((i = 0; i < cols; i++)); do # i is the row index of the transposed matrix
    for ((j = 0; j < rows; j++)); do # j is the column index of the transposed matrix
        linear_index=$((j * cols + i)) # index in the array
        ((j != 0)) && printf "\t" # print a tab if not the first element of the row
        printf "${a[${linear_index}]}" # print the element
    done
    printf "\n" # print a newline at the end of each row
done

或者使用我不喜欢的原始流量控制因为索引的对称性被破坏了:

#!/usr/bin/env bash
a=(1 1 1 1 1 9 3 4 5 5 6 7 8 9 7 3 6 8 9 1 3 4 2 1 4 6 4 4 7 7)
len=${#a[@]}
cols=5
for ((i = 0; i < cols; i++)); do
    printf ${a[i]} # treat the first element specially since I hate trailing whitespace
    for ((j = i + col; j < len; j += cols)); do
        printf "\t${a[j]}"
    done
    printf "\n"
done

答案 1 :(得分:1)

使用awk

定义列表a

$ a="1 1 1 1 1 9 3 4 5 5 6 7 8 9 7 3 6 8 9 1 3 4 2 1 4 6 4 4 7 7"

打印矩阵:

$ awk '{for (i=1;i<=5;i++){for (j=i;j<=NF;j=j+5)printf "%s ",$j; print""}}' <<<"$a"
1 9 6 3 3 6 
1 3 7 6 4 4 
1 4 8 8 2 4 
1 5 9 9 1 7 
1 5 7 1 4 7 

使用bash

$ a=(1 1 1 1 1 9 3 4 5 5 6 7 8 9 7 3 6 8 9 1 3 4 2 1 4 6 4 4 7 7)
$ for ((i=0;i<5;i++)) do for ((j=i;j<30;j=j+5)) do printf "%s " ${a[$j]}; done; echo "";done <<<"$a"
1 9 6 3 3 6  
1 3 7 6 4 4 
1 4 8 8 2 4 
1 5 9 9 1 7 
1 5 7 1 4 7 

如果要将其放入脚本中,而不是在命令行上执行,可能需要将其拆分为多行:

a=(1 1 1 1 1 9 3 4 5 5 6 7 8 9 7 3 6 8 9 1 3 4 2 1 4 6 4 4 7 7)
for ((i=0;i<5;i++))
do 
    for ((j=i;j<30;j=j+5)) 
    do 
        printf "%s " ${a[$j]}
    done
    echo ""
done <<<"$a"