【问题标题】:Storing output results of a command into a an array将命令的输出结果存储到数组中
【发布时间】:2018-08-30 11:03:31
【问题描述】:

我对 bash 命令输出有疑问。 我想将命令的结果保存到数组中,并将第一部分切割成 [0] 并将第二部分切割成 [1]

result=$(findId PATTERN | tr -s " " | cut -d " " -f 1)

findID 的输出是:

id errorcode nameOfProgramRunned

示例:

12345 "compilation problem" fullScan.java
12346 "other problem" basicTest.java

我想将id 保存到array[0]nameofProgramRunnedarray[1]

主要问题是我想避免两次执行命令,因为结果可能不同。

当前代码:

#!/bin/sh
echo 'Enter error code:'
read errorLine

result=$(findID PATTERN | awk '{print $1}')

while read -r line
do

    dir="/proj/jobs/"$line"/screenlog.*"

    if [ -e $dir ]
    then
        if grep -qi "$errorLine" $dir  
        then    
            echo -e "\e[101m$line:\e[49m"       
            grep $dir -i -e "$errorLine"

        fi  
    fi
done <<<"$result"

我想将 nameOfProgramRunned 添加到最终的 grep 中

我正在使用 bash

【问题讨论】:

  • 都到array[0]?您可能打算使用array[1]
  • 是的,这是一个错误。我不想保存到数组[1]
  • 如果findID 可以返回更易解析的内容,例如制表符分隔的记录或 JSON,那就更好了。
  • 已更改 findID 现在以制表符分隔
  • 你能澄清你想用多行输出发生什么吗?您想将id 保存到array[0],但在您的示例中,有两个ID,12345 和12346。您要为处理的每一行覆盖array,还是追加或其他内容?

标签: bash


【解决方案1】:

针对开放长度数组进行了编辑。

echo -e '12345\t"compilation problem"\tfullScan.java' | {
  IFS=$'\t' read -r -a FOO
  echo number: ${FOO[0]}
  echo string: ${FOO[1]}
  echo file: ${FOO[2]}
}

注意 IFS 设置为制表符分隔符

也来看看

help read # bash built in help

【讨论】:

  • 好主意,但如果我添加更多列,这个函数将是巨大且有问题的。目标是拥有 10 多列
【解决方案2】:

如果您的环境足够安全并且您可以信任您的输入,那么您也可以将行解析委托给 shell 本身。像这样的:

main () {
  findID \
  | while read line ; do
    eval "process_element $line"
    done
}

process_element () {
  local id problem program
  id="$1" ; problem="$2" ; program="$3"

  printf \
    "id: %s, problem: %s, program: %s\n" \
    "$id" \
    "$problem" \
    "$program"
  #do_your_things "$id" "$program"
}

findID () {
  echo '12345 "compilation problem" fullScan.java'
  echo '12346 "other problem" basicTest.java'
}

main

snippet on repl.it

【讨论】:

    【解决方案3】:

    您可以拆分管道以同时处理所有列。

    假设

    • findID 输出由 TAB 标记,而不是 " ",因此 cut 没有问题
    • 您可以将输出数组保存到文件 file1file2... 以便以后检索它们

    那么您可以通过以下方式分隔列:

    findId PATTERN   | tee >(cut -d$'\t' -f1 > file1) >(cut -d$'\t' -f2 > file2) >(cut -d$'\t' -f3 > file3)
    

    我已经使用以下最小示例测试了代码:

    echo -e '12345\t"compilation problem"\tfullScan.java
    12346\t"other problem"\tbasicTest.java'  | tee >(cut -d$'\t' -f1 > file1) >(cut -d$'\t' -f2 > file2) >(cut -d$'\t' -f3 > file3)
    

    即管道被拆分成不同的管道,每列一个

    感谢https://unix.stackexchange.com/questions/28503

    【讨论】:

      【解决方案4】:

      您可以使用 Perl 正则表达式来格式化输出并将其放入 Bash 中的关联数组中,但是我不建议在 Bash 中使用数组。如果 id 字段是唯一的,则关联数组将起作用。

      export errorLine='other problem'
      
      # Simulating the command output
      export result=$(cat <<EOF
      12345 "compilation problem" fullScan.java
      12346 "other problem" basicTest.java
      64321 "other problem" basicTest2.java
      EOF
      )
      
      # Replacing one doule quote by two double quote (escaping double quotes)
      result=$(perl -e '($str = $ENV{result}) =~ s/"/""/g; print "$str";')
      
      # Declaring an associative array
      declare -A errorsArray
      
      export paramID
      export paramName
      
      while read -r line
      do
        export linePerl="${line}"
      
        # Prints the columns enclosed by double quotes, which is why I escaped double quotes before
        export regexEval=$(perl -e '
          if($ENV{linePerl} =~ m/^(.+?)\s+""$ENV{errorLine}""\s+?(.+)$/s) {
            print "\"$1\";\"$2\"";
          }
        ')
      
        # Checks if the line matches the pattern
        if [[ ! -z "${regexEval}" ]]
        then
          paramID=$(perl -e '$str = ($ENV{regexEval} =~ m/;?"(.+?[^"])";?/g)[0]; print "$str";')
          paramName=$(perl -e '$str = ($ENV{regexEval} =~ m/;?"(.+?[^"])";?/g)[1]; print "$str";')
      
          errorsArray["${paramID}"]="${paramName}"
        fi
      done <<< "$result"
      
      # Prints the associative array
      for i in "${!errorsArray[@]}"
      do
        echo "${i}: ${errorsArray[$i]}"
      done
      
      # Output:
      #
      # 12346: basicTest.java
      # 64321: basicTest2.java
      #
      

      这是另一种解决方案,使用 CSV 文件而不是关联数组,我发现它更简单有效:

      export errorLine='other problem'
      
      # Simulating the command output
      export result=$(cat <<EOF
      12345 "compilation problem" fullScan.java
      12346 "other problem" basicTest.java
      64321 "other problem" basicTest2.java
      EOF
      )
      
      # Using Perl regular expression to format the output to CSV format
      perl -e '
      ($str = $ENV{result}) =~ s/"/""/g; # Replacing one doule quote by two double quote (escaping double quotes)
      
      while($str =~ m/^(.+)\s+""$ENV{errorLine}""\s+(.+)$/mg) {
        print "\"$1\";\"$2\"\n";
      }
      ' > output.csv
      
      # Printing "output.csv" file
      cat output.csv
      
      # Output:
      #
      # "12346";"basicTest.java"
      # "64321";"basicTest2.java"
      #
      
      while read -r line
      do
        export linePerl="${line}"
      
        # Removing the double quotes and printing
        perl -e '
          @str = $ENV{linePerl} =~ m/;?"(.+?[^"])";?/g;
          print "@str[0]: @str[1]\n"
        '
      done < output.csv
      
      # Output:
      #
      # 12346: basicTest.java
      # 64321: basicTest2.java
      #
      

      如果您想在 Perl 的上下文中访问环境变量,请不要忘记使用 export 将 Bash 环境变量公开给 Perl。

      【讨论】:

        猜你喜欢
        • 2017-09-20
        • 2013-01-12
        • 1970-01-01
        • 2012-01-03
        • 1970-01-01
        • 1970-01-01
        • 2014-06-14
        相关资源
        最近更新 更多