我正在编写一个脚本,它将文件中每行的前 3 个字母(通过使用 cut 来获取它们)与数组中的字符串进行比较。我已经环顾四周,但我找到的解决方案不适用于我的系统。
现在看起来像这样:
weekdays=([Mon]=1 [Tue]=1 [Wed]=1 [Thu]=1 [Fri]=1 [Sat]=1 [Sun]=1)
input="/Foo/Bar.log"
while read -r line
do
cutline="$(echo ${line} | cut -c 1-3"
if [[ ${weekdays["$cutline"]} ]]
then
echo "Match"
else
echo "No Match"
fi
done < ${input}
该线被正确切断,但测试期间的某些内容会返回误报,因为无论前 3 个字母是什么,它都会返回“匹配”。
当我使用 -x 检查脚本时,它向我展示了,而不是它使用的实际测试
[[ -n 1 ]]
当我用表达式测试它时,[ ]
它显示了1
它是否检查数组中的每个字符而不仅仅是整个单词,或者是否还有其他问题?
如果没有问题,是否有另一种方法可以将一行的前 3 个字母与数组中的所有字母进行比较,然后再继续下一个字母?
附带说明:我确实正在运行 Bash 4,所以关联数组应该可以工作
答案1
基本错误是您实际上并未声明关联数组:
$ weekdays=(["Mon"]=1 ["Tue"]=1 ["Wed"]=1 ["Thu"]=1 ["Fri"]=1 ["Sat"]=1 ["Sun"]=1)
$ echo ${weekdays[@]}
1
$ echo ${weekdays[0]}
1
$ echo ${weekdays[2]}
$
我不完全确定 bash 如何处理它以及为什么它只需要一个1
,但我确信这不是一个关联数组。正如man bash
(强调我的)中所解释的:
如果使用语法 name[下标]=value 分配任何变量,则会自动创建索引数组。下标被视为必须计算为数字的算术表达式。要显式声明索引数组,请使用declare -a name(请参阅下面的SHELL BUILTIN命令)。声明 -a name[下标] 也被接受;下标被忽略。
关联数组是使用声明 -A 名称创建的。
因此,请尝试这样做,它将按您的预期工作:
declare -A weekdays=(["Mon"]=1 ["Tue"]=1 ["Wed"]=1 ["Thu"]=1 ["Fri"]=1 ["Sat"]=1 ["Sun"]=1)
也就是说,您的脚本比您需要的要复杂一些。这是使用相同方法的更简单的版本:
#!/bin/bash
declare -A weekdays=(["Mon"]=1 ["Tue"]=1 ["Wed"]=1 ["Thu"]=1 ["Fri"]=1 ["Sat"]=1 ["Sun"]=1)
input="/Foo/Bar.log"
cut -c 1-3 "$input" | while read -r line; do
if [[ ${weekdays["$line"]} ]]
then
echo "Match : $cutline : ${weekdays[$line]}"
else
echo "No Match"
fi
done
虽然我可能会这样做:
#!/bin/bash
cut -c 1-3 "$1" | while read -r line; do
case $line in
"Mon"|"Tue"|"Wed"|"Thu"|"Fri"|"Sat"|"Sun")
echo yes;;
*)
echo no;;
esac
done
然后,使用目标文件名作为参数运行脚本:
script.sh /Foo/Bar.log"
答案2
我会使用一次文本处理工具的调用来处理文本,不是每行输入都有几个工具:
awk -v 'weekday=(Mon|Tue|Wed|Thu|Fri|Sat|Sun)' '
{print ($0 ~ "^" weekday ? "" : "No ") "Match"}' < "$input"
如果您需要为输入的每一行运行特定的应用程序,则可以使用循环,但如果只是文本处理(例如将行输出到某个文件),则awk
可以这样做:
awk -v 'weekday=Mon|Tue|Wed|Thu|Fri|Sat|Sun' '
(day = substr($0, 1, 3)) ~ weekday {
print substr($0, 4) > day ".txt"
} < "$input"