我的bash shell脚本正在使用Bash 3.2.5。 我有一个包含以下内容的输入文件:
1234567
2345678
3456789
4567890
和一个包含以下代码的bash shell脚本:
#!/bin/bash
content=($(cat data.txt | awk {'print $1'}))
for (( i=0 ; i<${#content[@]} ; i++ ))
do
if (( i==0 ))
then
ele=`echo ${content[$i]}`
else
ele=`echo ","${content[$i]}`
fi
all=`echo $all$ele`
done
# should be a string of csv: works on bash 3.2.5 - fails on bash 4.1.2
echo $all
当使用Bash 3.2.5运行时,它输出:(预期输出;正确)
1234567,2345678,3456789,4567890
但是当使用Bash 4.1.2运行时,它输出:(文件中的最后一个数字;不正确)
,4567890
为什么Bash 4.1.2中的相同代码失败?
答案 0 :(得分:2)
使用echo
设置变量的内容只是简单..错误。当我说错了,我的意思是,你可以做到,但在这种情况下,绝对没有理由使用command substitution
语句的echo
来填充变量。同样,没有理由使用cat
管道传输到awk
来填充数组。只需简单的重定向即可轻松完成数组填充。
通过消除所有不需要的command substitution
echo
和piped
命令,您可以消除大量错误机会。这是一个适用于3或4的更新。
#!/bin/bash
content=( $( <data.txt) )
for (( i=0 ; i<${#content[@]} ; i++ ))
do
if (( i==0 ))
then
ele="${content[i]}"
else
ele=",${content[i]}"
fi
all="${all}${ele}"
done
echo $all
<强>输出强>
$ bash bash34fail.sh
1234567,2345678,3456789,4567890
答案 1 :(得分:2)
这无助于理解您所看到的症状,但您的代码可以完全重写为
paste -d , -s data.txt
如果你想使用bash结构:
mapfile -t numbers < data.txt # read the lines of the file into an array
(IFS=,; echo "${numbers[*]}") # join the array with a comma
但是,请检查您的数据文件是否包含回车符:oc -d data.txt
并使用dos2unix
或sed -i 's/\r$//' data.txt
答案 2 :(得分:0)
将突出的评论转换为答案。
分配如:
ele=`echo ","${content[$i]}"`
all=`echo $all$ele`
不应该使用反向标记`…`
或$(…)
命令替换;你应该写简单
all="$all$sep${content[$i]}"
您可以在循环之前获得sep=""
,并在分配给所有人之后获得sep=","
。
另外,FWIW,我在Mac OS X 10.10.2上尝试使用Bash版本3.2.57(1)-release和4.3.27(2)-release的脚本,并获得相同的正确(预期)输出都。
您是否查看过bash -x yourscript.sh
会发生什么?这是一个基本且非常重要的shell脚本调试技术。
您是否检查了数据文件以获取Windows样式的CRLF行结尾?
当我的data.txt
文件具有Windows样式的CRLF(回车,换行)行结尾时,我得到了&#39; Bash 4.1.2&#39;输出。当我的data.txt
文件具有Unix风格的NL(换行,也就是换行)行结尾时,我得到了&#39; Bash 3.2.5输出。
您是否以某种方式通过Windows系统将材料复制到运行Bash 4.1.2的计算机上?或者,换句话说,您确定在要测试它的两台机器上运行完全相同的数据文件吗?
我将脚本简化为:
sep=""
all=""
while read number
do
all="$all$sep$number"
sep=","
done < data.txt
echo "$all"
还有其他方法可以达到相同的效果,但这种方法非常简单,并且不会使用任何子壳,这与使用大量脚本的原始脚本不同。
答案 3 :(得分:0)
这个问题的答案是;由于文件中的crlf在4.1.2上运行的脚本正在使用。
Jonathan Leffler和Glenn jackman让我回答了这个问题。 我在运行bash 4.1.2的linux机器上创建的文件是用crlf创建的dos风格。使用lf作为行结束标记创建3.2.5文件。我没想到要查看数据文件本身,我很清楚这会导致过去与其他情况一起出现问题。
我从上面的所有帖子中了解了不同的更好的方法,我会全力以赴。
再次感谢你。
以下是我正在研究的两个系统的更多细节:
bash 4.2.1:
$ uname -a
Linux n0c 2.6.32-358.18.1.el6.x86_64 #1 SMP Fri Aug 2 17:04:38 EDT 2013 x86_64 x86_64 x86_64 GNU/Linux
$ bash -version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
bash 3.2.5:
[root@ww ~]# uname -a
Linux ww.com 2.6.18-028stab101.1-ent #1 SMP Sun Jun 24 20:22:25 MSD 2012 i686 i686 i386 GNU/Linux
[root@ww ~]# bash -version
GNU bash, version 3.2.25(1)-release (i386-redhat-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.