【问题标题】:Shell not evaluating multiple conditions in IF statementShell 不评估 IF 语句中的多个条件
【发布时间】:2019-12-04 21:16:13
【问题描述】:

我想根据两个条件将文件分类到文件夹中,但它不会评估这两个条件。条件基于从与特定主题相对应的文本文件 (index.txt) 读取的值,并且值编码为 0 或 1

Subid   DX    SEX
XXXX    0      0
YYYY    1      0

代码如下

    #!/bin/sh 
    d=XXXX
    dx=$(awk '{if($1=='$d'){print $2}}' index.txt)
    sex=$(awk '{if($1=='$d'){print $3}}' index.txt)
    if [ "$dx" == "0" ] && [ "$sex" == "0" ];then
     commands
    fi

我尝试使用双括号 [[ <condition 1> ]] && [[ <condition 2> ]];、折叠括号 if [ <condition1> && <condition2> ];、括号,并使用 -eq 代替 ==,但它们仍然没有进行评估,也没有打印错误。我错过了什么?

【问题讨论】:

  • $x 和 $y 设置在哪里?正如你所展示的,它们将是空字符串。
  • 使用=,而不是==,使用[ ... ]。
  • 请注意,shell 正在评估第一个条件;它只是发现""(因为x 未定义)不等于"0",因此&& 阻止了第二个条件的评估。
  • 已编辑以显示变量。不幸的是,使用单个 = 并没有做到这一点
  • 使用您提供的文件 (index.txt) 运行代码,您的 $dx 和 $sex 变量为空

标签: bash shell if-statement


【解决方案1】:

调试 shell 脚本时最有用的技巧之一是 set -x(或使用 sh -x 运行整个脚本)。这使得 shell 在执行每个命令时打印它们的等价物,因此您可以更好地了解实际发生的情况以及它是否符合您的预期。让我们在你的脚本上试试吧:

$ sh -x reader.sh
+ d=XXXX
++ awk '{if($1==XXXX){print $2}}' index.txt
+ dx=
++ awk '{if($1==XXXX){print $3}}' index.txt
+ sex=
+ '[' '' == 0 ']'

请注意,它将dx 和sex 都设置为空字符串。如果您查看正在执行的 awk 脚本,您就会明白原因:XXXX 周围没有双引号,因此 awk 将其视为变量名,而不是要匹配的文字字符串。

您可以添加双引号,但这并不是最好的方法;将文字字符串粘贴到可执行代码(在这种情况下为 awk 脚本)可能会使部分字符串被误认为可执行代码,这可能会产生非常奇怪/糟糕的后果。做这种事情的更好方法是将数据传递给作为数据,通过使用awk 的-v 选项设置一个变量,然后使用它。比如:

$ awk -v d="XXXX" '{if($1==d){print $2}}' index.txt
0

嘿,它打印了正确的东西!所以这是你的脚本的一个版本:

#!/bin/sh
d=XXXX
dx=$(awk -v d="$d" '{if($1==d){print $2}}' index.txt)
sex=$(awk -v d="$d" '{if($1==d){print $3}}' index.txt)
if [ "$dx" = "0" ] && [ "$sex" = "0" ];then
    commands
fi

请注意,名为d 的awk 变量与名为d 的shell 变量没有内在联系; -v d="$d" 位将 shell 变量复制到同名的 awk 变量中。另外,我在比较中将== 切换为=,因为这是[ ] 中的标准字符串相等运算符。 bash 允许 == 作为同义词,但并非所有 shell 都这样做;如果您是专门为 bash 编写的,则应使用特定的 bash shebang 行(#!/bin/bash 或 #!/usr/bin/env bash)而不是 #!/bin/sh。

(实际上,我建议您使用 bash shebang,因为如果您不清楚什么是标准 shell 语法和什么是 bash 扩展,那么您可能无论如何都不能以可移植方式编写,因此明确请求 bash 更安全。而且如果你这样做,你不妨切换到[[ ]] 而不是[ ],因为它避免了[ ] 表达式遭受的许多语法上的怪异。)

【讨论】:

  • 它在我的 awk 语法中读取得很好,但我运行 sh -x 并看到 Windows 将那些不可见的托架添加到索引中的行中,这就是原因。非常感谢!
【解决方案2】:

问题不在于您的条件,而在于您使用 awk 设置的变量。

尝试以下方法来设置变量:

#!/bin/sh
d=XXXX
dx=$(awk '{if ($1 ~ /'$d'/) print $3}' index.txt)
sex=$(awk '{if ($1 ~ /'$d'/) print $3}' index.txt)
if [ "$dx" = "0" ] && [ "$sex" = "0" ];then
echo "works"
fi

【讨论】:

  • 使用== 而不是= 限制了此代码可以使用的/bin/sh 的实现。 The POSIX test specification只定义了=,不支持==的实现(使用时总是报错,返回false)并不少见。见[: Unexpected operator in shell programming。
  • (澄清我所说的“并不罕见”——想想“在 Ubuntu 上开箱即用地安装”)。
  • 谢谢@CharlesDuffy,将我的答案更正为符合 POSIX。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-17
  • 1970-01-01
  • 2015-08-22
  • 1970-01-01
相关资源
最近更新 更多