【问题标题】:Bash Issue: AWK重击问题:AWK
【发布时间】:2016-10-06 14:46:33
【问题描述】:

我休息后回来工作,发现我的 Bash 脚本不像以前那样工作了。下面的代码将抓取和过滤文件中的内容。这是该文件的内容:

# A colon, ':', is used as the field terminator.  A new line terminates
# the entry.  Lines beginning with a pound sign, '#', are comments.
#
# Entries are of the form:
#   $ORACLE_SID:$ORACLE_HOME:<N|Y>:
#
# The first and second fields are the system identifier and home
# directory of the database respectively.  The third filed indicates
# to the dbstart utility that the database should , "Y", or should not,
# "N", be brought up at system boot time.
#
# Multiple entries with the same $ORACLE_SID are not allowed.
#
#
OEM:/software/oracle/agent/agent12c/core/12.1.0.3.0:N
*:/software/oracle/agent/agent11g:N
dev068:/software/oracle/ora-10.02.00.04.11:Y

dev299:/software/oracle/ora-10.02.00.04.11:Y

xtst036:/software/oracle/ora-10.02.00.04.11:Y

xtst161:/software/oracle/ora-10.02.00.04.11:Y
dev360:/software/oracle/ora-11.02.00.04.02:Y
dev361:/software/oracle/ora-11.02.00.04.02:Y
xtst215:/software/oracle/ora-11.02.00.04.02:Y
xtst216:/software/oracle/ora-11.02.00.04.02:Y
dev298:/software/oracle/ora-11.02.00.04.03:Y
xtst160:/software/oracle/ora-11.02.00.04.03:Y

代码用来生成并放入数组的内容:

dev068
dev299
xtst036
xtst161
dev360
dev361
xtst215
xtst216
dev298
xtst160

它会查看文件 (oratab),找到数据库名称(例如 xtst160),然后将它们放入一个数组中。然后我在脚本后面的其他任务中使用了这个数组。以下是相关的 Bash 脚本代码:

# Collect the databases using a mixture of AWK and regex, and throw it into an array.
printf "\n2) Collecting databases on %s:\n" $HOSTNAME
declare -a arr_dbs=(`awk -F: -v key='/software/oracle/ora' '$2 ~ key{print $ddma_input}' /etc/oratab`)

# Loop through and print the array of databases.
for i in ${arr_dbs[@]}
do
        printf "%s  " $i
done

似乎没有人修改过代码或 oratab 文件格式已更改。所以我不是 100% 确定现在发生了什么。它不是抓取几个字符,而是抓取整行:

dev068:/software/oracle/ora-10.02.00.04.11:Y 

我正在尝试更多地了解 Bash 和正则表达式,但我很困惑。绝对不是我的强项。 非常感谢对 awk 行的详细解释。

【问题讨论】:

  • ddma_input 是您的 awk 脚本中未设置的变量,因此它被强制转换为 0,因此您最终会得到打印整行的 print $0
  • @TomFenech 好吧,我不认为你错了。我在声明行之前做了一个printf "%s" $ddma_input,它没有打印任何东西。但是在脚本的开头,当我有ddma_input = $1 时,我会回显/打印它,它会显示正确的输入。完全奇怪。不确定它是如何被取消/更改的,因为除了一些被调用 ($ddma_input) 且未分配的函数之外,它没有在其他任何地方使用。
  • 如果您想在 awk 脚本中使用 shell 变量,那么您需要使用 -v 将其传递给脚本,就像您已经使用 key 所做的那样。我不知道这是如何工作的。
  • 可以理解!它相当笨拙。我发现了错误。我们更改了传入参数的数量和接收它们的顺序。糟糕...感谢您的宝贵时间,@TomFenech!
  • @Erik,如果以不太可能帮助他人的方式解决了这个问题,请考虑将其删除。

标签: linux bash shell awk


【解决方案1】:

我发现了错误。我们更改了传入的参数数量和接收顺序。

【讨论】:

    【解决方案2】:

    打印 $1 而不是 $ddma_input 并解决问题。

    declare -a arr_dbs=(`awk -F ":" -v key='/software/oracle/ora' '$2 ~ key{print $1}' /etc/oratab`)
    
    # Loop through and print the array of databases.
    for i in ${arr_dbs[@]}
    do
            printf "%s  " $i
    done
    

    【讨论】:

    • 这在几个方面仍然存在问题。一般来说,arr=( $(...) ) 是一种反模式:IFS 拆分和全局扩展都处于活动状态,这比使用 readarraymapfileread -a 填充数组更容易出错。
    • ...和不带引号的for i in ${arr[@]} 具有与for i in ${arr[*]} 相同的错误;它需要是for i in "${arr[@]}" 以避免进行自己的字符串拆分和全局扩展。同样,printf 中的$i 应该是"$i"
    【解决方案3】:

    您可以在本机 bash 中轻松实现这一切,而无需任何外部工具:

    arr_dbs=( )
    while IFS= read -r line; do
      case $line in
        "#"*)                        continue ;;
        *:/software/oracle/ora*:*)   arr_dbs+=( "${line%%:*}" ) ;;
      esac
    done </etc/oratab
    
    printf '  %s\n' "${arr_dbs[@]}"
    

    这实际上避免了您在原始实现中遇到的一些错误。假设您有如下一行:

    *:/software/oracle/ora-default:Y
    

    如果您不小心处理该*,则在发生扩展时,shell 会将其替换为当前目录中的文件名列表。

    在这种情况下,“无论何时发生扩展”是什么意思?嗯:

    # this will expand a * into a list of filenames during the assignment to the array
    arr=( $(echo "*") )    # vs the correct read -a arr < <(echo "*")
    
    # this will expand a * into a list of filenames while generating items to iterate over
    for i in ${arr[@]}     # vs the correct for i in "${arr[@]}"
    
    # this will expand a * into a list of filenames while building the argument list for echo
    i="*"
    echo $i                # vs the correct printf '%s\n' "$i"
    

    注意printf 的使用超过echo -- 请参阅the POSIX specification of echo 的应用使用部分。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-13
      • 2019-12-14
      • 1970-01-01
      • 1970-01-01
      • 2011-04-29
      • 2013-02-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多