为什么这个shell脚本在有和没有shebang的情况下表现不同?

时间:2012-12-02 14:39:44

标签: shell

我正在关注一个linux shell编程指南,以提高我对shell的熟练程度。 今天,我到达了嵌套for循环部分。

以下脚本在终端上打印棋盘。

for (( i = 1; i <= 9; i++ )) ### Outer for loop ###
do
   for (( j = 1 ; j <= 9; j++ )) ### Inner for loop ###
   do
        tot=`expr $i + $j`
        tmp=`expr $tot % 2`
        if [ $tmp -eq 0 ]; then
            echo -e -n "\033[47m "
        else
            echo -e -n "\033[40m "
        fi
  done
 echo -e -n "\033[40m" #### set back background colour to black
 echo "" #### print the new line ###
done

它运作正常。 我立刻在它的开头加了一个shibang,看起来像是

#!/bin/sh
for (( i = 1; i <= 9; i++ )) ### Outer for loop ###
do
   for (( j = 1 ; j <= 9; j++ )) ### Inner for loop ###
   do
        tot=`expr $i + $j`
        tmp=`expr $tot % 2`
        if [ $tmp -eq 0 ]; then
            echo -e -n "\033[47m "
        else
            echo -e -n "\033[40m "
        fi
  done
 echo -e -n "\033[40m" #### set back background colour to black
 echo "" #### print the new line ###
done

但是,现在,每个白色/黑色块都会打印整行。

任何人都可以帮助我理解为什么? (我在Mac Snow Leopard下运行shell)。 谢谢! 威廉


刚:

只是一个更新,我发现如果我使用“#!/ bin / bash”,它运行正常。 所以这是内部实现sh的问题?

谢谢!

3 个答案:

答案 0 :(得分:1)

或许

#!/bin/bash

如果您想指定将使用哪个程序来解释此文本文件,请输入#!

答案 1 :(得分:0)

问题是您正在使用echo,但遗憾的是,即使在符合POSIX标准的系统上,此命令行为也无法预测。

-n作为echo参数传递或参数中存在转义序列时,未指定回应行为。您的代码正在使用这两种非便携式构造。而且,它也使用不可移植的-e基础。

查看"APPLICATION USAGE" chapter in the echo POSIX manual page了解详情。

您应该使用printf代替echoprintf是可移植的,并且已创建以克服echo限制。

#!/bin/sh
for (( i = 1; i <= 9; i++ )) ### Outer for loop ###
do
   for (( j = 1 ; j <= 9; j++ )) ### Inner for loop ###
   do
        tot=`expr $i + $j`
        tmp=`expr $tot % 2`
        if [ $tmp -eq 0 ]; then
            printf "\033[47m "
        else
            printf "\033[40m "
        fi
  done
 printf "\033[40m" #### set back background colour to black
 echo "" #### print the new line ###
done

顺便说一下,这段代码可以这样简化(至少同时使用ksh和bash):

for (( i = 1; i <= 9; i++ )); do
  for (( j = 1 ; j <= 9; j++ )); do
    printf "\033[%dm " $((((i+j)%2)?40:47))
  done
  printf "\033[40m\n"
done

答案 2 :(得分:-1)

echo是内置的shell(尽管它也可以在/bin/echo中单独使用),因此根据shell的版本,它的行为可能会有所不同。在我的系统上(OS X Mountain Lion):

$ which sh
/bin/sh
$ /bin/sh --version
GNU bash, version 4.2.37(2)-release (i386-apple-darwin12.2.0)
Copyright (C) 2011 Free Software Foundation, Inc.
$ /bin/sh -c "echo -e -n '\e[0;34mtest'"
-e -n \e[0;34mtest   # incorrect

$ which bash
/opt/local/bin/bash
$ /opt/local/bin/bash --version
GNU bash, version 4.2.37(2)-release (i386-apple-darwin12.2.0)
Copyright (C) 2011 Free Software Foundation, Inc.
...
$ /opt/local/bin/bash -c "echo -e -n '\e[0;34mtest'"
test    # blue and without a newline. correct

因此,在我的Mac上/bin/sh不支持-e-n个参数,而/opt/local/bin/bash则支持,类似于您所看到的。

顺便说一下,您可以使用$(( ... ))算术扩展或let进行计算:

# with arithmetic expansion:
tmp=$(( (i + j) % 2 ))   # $i and $j can be used but are not necessary

# with let:
let tmp=(i+j)%2   # no spaces allowed

# or just calculate inside the if statement directly:
if (( (i + j) % 2 == 0 )); then
....