为什么这个 shell 脚本在有和没有 shebang 时的行为不同

  • 本文关键字:shebang shell 脚本 shell
  • 更新时间 :
  • 英文 :


我正在遵循Linux shell编程指南来提高我对shell的熟练程度。今天,我到达了嵌套循环的部分。

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

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 "33[47m "
        else
            echo -e -n "33[40m "
        fi
  done
 echo -e -n "33[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 "33[47m "
        else
            echo -e -n "33[40m "
        fi
  done
 echo -e -n "33[40m" #### set back background colour to black
 echo "" #### print the new line ###
done

然而,现在,每个白色/黑色块都打印成整行。

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


岗:

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

谢谢!

也许#!/bin/bash

当您要指定将使用哪个程序来解释此文本文件时,请放置#!

问题是您正在使用echo但不幸的是,即使在符合 POSIX 的系统上,此命令行为也是不可预测的。

-n作为参数传递echo或者当参数中存在转义序列时,未指定回显行为。您的代码正在使用这两种不可移植的结构。此外,它还使用非便携式-e bashism。

有关详细信息,请查看echo POSIX手册页中的"应用程序使用"一章。

您应该使用 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 "33[47m "
        else
            printf "33[40m "
        fi
  done
 printf "33[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 "33[%dm " $((((i+j)%2)?40:47))
  done
  printf "33[40mn"
done
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
....

最新更新