Bash:测试多个变量的相互平等?

时间:2012-01-10 23:27:22

标签: bash conditional

测试几个变量是否相等的正确方法是什么?

if [[ $var1 = $var2 = $var3 ]] # syntax error

是否有必要写下面的内容?

if [[ $var1 = $var2 && $var1 = $var3 && $var2 = $var3 ]] # cumbersome
if [[ $var1 = $var2 && $var2 = $var3 && $var3 = $var4 ]] # somewhat better

不幸的是,我能找到的优秀的Advanced Bash Scripting Guide和其他在线资源并没有提供这样的例子。

我的特别动机是测试几个目录是否都有相同数量的文件,使用ls -1 $dir | wc -l来计算文件。

注意
“var1”等是示例变量。我正在寻找任意变量名称的解决方案,而不仅仅是具有可预测数字结尾的变量名称。

更新
我接受了Richo的答案,因为它是最普遍的。但是,我实际上是在使用Kyle,因为它是最简单的,我的输入可以保证避免警告。

感谢大家的建议。

5 个答案:

答案 0 :(得分:3)

如果你想测试任意数量项目的相等性(我们称之为$ item1-5,但它们可能是一个数组

st=0
for i in $item2 $item3 $item4 $item5; do
    [ "$item1" = "$i" ]
    st=$(( $? + st ))
done

if [ $st -eq 0 ]; then
    echo "They were all the same"
fi

答案 1 :(得分:2)

如果它们是单个单词,你可以非常便宜。

varUniqCount=`echo "${var1} ${var2} ${var3} ${var4}" | sort -u | wc -l`
if [ ${varUniqCount} -gt 1 ]; then
   echo "Do not match"
fi

答案 2 :(得分:1)

(编辑包括用于解决Keith Thompson注意到的问题的分隔符)

将变量值作为字符串处理,您可以将它们与合适的分隔符连接起来并进行一次比较:

if [[ "$var1|$var2|$var3" = "$var1|$var1|$var1" ]]

我使用=而非= =因为==不是[[]]内的相等比较,它是一种模式匹配。

答案 3 :(得分:1)

检查的传递方法

#!/bin/bash

var1=10
var2=10
var3=10

if [[ ($var1 == $var2) && ($var2 == $var3) ]]; then 
    echo "yay"
else
    echo "nay"
fi

输出:

[jaypal:~/Temp] ./s.sh 
yay

注意:

由于您已在问题中声明您的目标是测试具有相同数量文件的多个目录,因此我想到了以下解决方案。我知道这不是你要求的,所以请随意忽略它。

步骤1:

确定给定目录中的文件数。此命令也会查看子目录内部,但可以使用-depth find选项控制该命令。

[jaypal:~/Temp] find . -type d -exec sh -c "printf {} && ls -1 {} | wc -l " \;
.       9
./Backup       7
./bash       2
./GTP      22
./GTP/ParserDump      11
./GTP/ParserDump/ParserDump       1
./perl       7
./perl/p1       2
./python       1
./ruby       0
./scripts      22

步骤2:

这可以与Step1结合使用,因为我们只是将内容重定向到文件。

[jaypal:~/Temp] find . -type d -exec sh -c "printf {} && ls -1 {} | wc -l " \; > file.temp

步骤3:

使用以下命令,我们将在file.temp中查看两次,它将为我们提供具有相同文件数的目录列表。

[jaypal:~/Temp] awk 'NR==FNR && a[$2]++ {b[$2];next} ($2 in b)' file.temp file.temp | sort -k2
./GTP/ParserDump/ParserDump       1
./python       1
./bash       2
./perl/p1       2
./Backup       7
./perl       7
./GTP      22
./scripts      22

答案 4 :(得分:1)

对于您的具体情况,这应该有效:

distinct_values=$(for dir in this_dir that_dir another_dir ; do ls -l "$dir" | wc -l ; done | uniq | wc -l)
if [ $distinct_values -eq 1 ] ; then
    echo All the same
else
    echo Not all the same
fi

说明:

  • ls -l "$dir"列出目录中的文件和子目录,每行一个(省略点文件)。
  • 通过wc -l管道输出为您提供目录中的文件数。
  • 对列表中的每个目录连续执行此操作会为您提供一个列表,其中包含每个目录中的文件数;如果每个中有7个,则给出3行,每行包含数字7
  • 通过uniq进行管道消除了连续的重复行。
  • 管道 wc -l会为您提供不同行的数量,当且仅当所有目录包含相同数量的文件时才会为1。

请注意,第4阶段的输出不一定能为您提供目录中不同数量的文件数量; uniq仅删除相邻的重复项,因此如果输入为7 6 7,则两个7将不会合并。但如果它们全部相同,它会将所有行合并为1

这是Unix命令行的强大功能:将小工具放在一起做有趣且有用的事情。 (给我看一个可以做到这一点的GUI!)

对于存储在变量中的值,请将第一行替换为:

distinct_values=$(echo "$this_var" "$that_var" "$another_var" | fmt -1 | uniq | wc -l)

这假设变量的值不包含空格。