【发布时间】:2014-07-01 01:00:18
【问题描述】:
我编写了一个脚本来对一些大型平面文件进行子集化,其中子集的整数个数(即 $increment)作为用户输入变量。仅当此输入参数是 odd 整数时,我才观察到一种奇怪的行为(bash 语法错误)。为了(略微)提高清晰度,我在原始 shell 脚本的精简版本中复制了这个错误行为。我无法提供平面文件,但希望有 shell/bash 专业知识的人可以通过查看代码和错误消息来诊断这里发生了什么(我已经通过http://www.shellcheck.net/ 运行了这个并且没有发现任何严重的问题) .
当 $increment 设置为偶数(例如 8)时,shell 脚本执行时不会出错,并为 while 循环的每次迭代输出所需的打印语句(参见下面的“注意”)。以下是这些打印语句的一些示例输出:
Line of interest: span2=84688
Line of interest: span2=85225
Line of interest: span2=86323
...
但是,当 $increment 为奇数时(例如 9),脚本会在第 48 行“span2=$(($line2-$last2))”处失败,并显示错误语句:
test_case.sh: line 48: 153026
153027-77419: syntax error in expression (error token is "153027-77419")
这很奇怪,因为前面的 echo print 语句输出“感兴趣的行:span2=75278”表明算术表达式正在子shell 中计算,没有错误,就在失败的行之前。所以很明显,这里减去的整数没有什么特别之处,但奇怪的是,例如,当表达式参数 $line2 等于“ 153027"。不过,我不确定这是否/如何与语法错误相关。
#!/bin/bash
set -e
increment=9
file1="path/to/file1"
file2="path/to/file2"
file3="path/to/file3"
# End index of header in first file
file1_start=2138
midpoint=$(( $file1_start + 1 ))
file1_wc=($(wc $file1))
file2_wc=($(wc $file2))
file3_wc=($(wc $file3))
# Get a line count for the three different flat text files, as an upper bound index
ceil1=${file1_wc[0]}
ceil2=${file2_wc[0]}
ceil3=${file3_wc[0]}
# Initialize end point indices
line="$(head -$midpoint $file1 | tail -1 | awk '{print $1;}')"
line2=$(grep -n -e "$line" $file2 | cut -f1 -d:)
line3=$(grep -n -e "$line" $file3 | cut -f1 -d:)
# Initialize starting point indices
last1=$midpoint
last2=$line2
last3=$line3
# Update "midpoint" index
midpoint=$(($midpoint+$ceil1/$increment))
while [ $midpoint -lt $ceil1 ]
do
line="$(head -$midpoint $file1 | tail -1 | awk '{print $1;}')"
line2=$(grep -n -e "$line" $file2 | cut -f1 -d:)
line3=$(grep -n -e "$line" $file3 | cut -f1 -d:)
# Calculate range of indices for subset number $increment
span1=$(($midpoint-$last1))
echo "Line of interest: span2=$(($line2-$last2))"
# ***NOTE***: The below statement is where it is failing for odd $increment
span2=$(($line2-$last2))
span3=$(($line3-$last3))
# Set index variables for next iteration of file traversal
index=$(($index+1))
last1=$midpoint
last2=$line2
last3=$line3
# Increment midpoint index variable
midpoint=$(($midpoint+$ceil1/$increment))
done
非常感谢您的反馈,在此先感谢。
更新:通过添加“set -x”并查看调用堆栈,我确定表达式
line2=$(grep -n -e "$line" $file2 | cut -f1 -d:)
greping 不止一行。因此,在我上面提供的示例中,$line2 等于“153026\n153027”,并且不是减法的合理参数,因此存在语法错误。解决此问题的一种方法是通过管道连接到头部,例如
line2=$(grep -n -e "$line" $file2 | cut -f1 -d: | head -1)
只考虑 grep 产生的第一行。
【问题讨论】:
-
您是否尝试过将
set -x放入脚本中以便观察其执行情况?这是调试 shell 脚本的常用方法。 -
检查坏行中的非打印字符
-
确保使用 bash 运行它:
bash your_script.sh。你能展示你的bash版本吗?bash --version -
dos2unix myScriptName?修复了 S.O. 上 1/2 的神秘问题。 :-) 。祝你好运。 -
您可以回答自己的问题。我只是给你调试提示,我没有弄清楚解决方案。