【问题标题】:Shell script hangs when i switch to bash - Linux [duplicate]当我切换到 bash 时,Shell 脚本挂起 - Linux [重复]
【发布时间】:2016-11-29 02:07:04
【问题描述】:

我对 Linux 非常陌生(来自 Windows)并尝试编写一个我希望可以在多个系统上执行的脚本。我尝试为此使用 Python,但也很难找到它。这是我目前所拥有的:

cd /bin
bash
source compilervars.sh intel64
cd ~
exit #exit bash
file= "~/a.out"
if[! -f "$file"]
then
icc code.c
fi

#run some commands here...

脚本挂在第二行 (bash)。我不确定如何解决这个问题,或者我是否做错了。请指教。

另外,关于如何在同一网络上的多个系统上运行此脚本的任何提示?

非常感谢。

【问题讨论】:

  • 你是如何运行这个脚本的?它的目的是什么?你为什么要在中间调用 bash,而不是一开始就作为 bash 运行?
  • 不确定你是否掌握了如何编写和运行 bash 脚本的基础知识。看看:stackoverflow.com/documentation/bash/300/…
  • 在您来这里请人为您调试之前,请将您的脚本提交给shellcheck.net

标签: linux bash shell


【解决方案1】:

我相信你想做的事:

#!/bin/bash

source /bin/compilervars.sh intel64

file="$HOME/a.out"

if [ ! -f "$file" ]; then
    icc code.c
fi

您可以将它放在一个文件中,并使用chmod +x myscript 使其可执行。然后你可以用./myscript 运行它。或者,您可以使用 bash myscript 运行它。

您的脚本毫无意义。第二行将打开一个新的bash 会话,但它会坐在那里直到您退出它。此外,很少需要来回更改目录。要在另一个目录中执行单个命令,通常会这样做

( cd /other/place && mycommand )

( ... ) 告诉外壳您想在子外壳中执行此操作。 cd 发生在该子外壳中,完成后您不必返回 cd。如果cd 失败,该命令将不会运行。

例如:您可能希望在编译代码时确保您在$HOME

if [ ! -f "$file" ]; then
  ( cd $HOME && icc code.c )
fi

...甚至从变量file 中选择目录名称并使用它:

if [ -f "$file" ]; then
  ( cd $(dirname "$file") && icc code.c )
fi

分配给变量需要按照我写的方式进行,= 周围没有空格。

同样,if 之后和[ ... ] 内部需要有空格,就像我在上面写的那样。

我也倾向于在脚本中使用$HOME 而不是~,因为它更具描述性。

【讨论】:

  • 这行得通!非常感谢@Kusalananda。我不知道空格很重要(也许还有线条?)。很高兴知道。我将对此进行更多研究。
  • @Samy Lines 很重要,尤其是当您在上面输入内容时。 ;-) 对不起,那是个玩笑。空行无关紧要。空间在地方很重要。命令后面需要空格。 [ 实际上是一个命令,通常内置在 shell 中(参见 man [),但您也可以将其键入为 /bin/[,即 if /bin/[ -f "$file"; then(是的,匹配的 ] 现在已经消失了,奇怪啊?),这与if test -f "$file"; then相同。我怎么能让你更困惑? ;-)
【解决方案2】:

shell 脚本不是输入终端的击键记录。如果你写一个这样的脚本:

command1
bash
command2

这并不意味着脚本会切换到bash,然后在不同的shell中执行command2。这意味着将运行bash。如果有控制终端,该 bash 将向您显示提示并等待输入命令。您必须输入 exit 才能退出该 bash。只有这样,原始脚本才会继续使用command2

没有办法在中途将脚本切换到不同的 shell。有一些方法可以模拟这一点。脚本可以使用不同的 shell 重新执行自身。为了做到这一点,脚本必须包含检测它正在被重新执行的逻辑,以便它可以防止再次重新执行自身,并跳过一些不应该运行两次的代码。

this script 中,我实现了这样一个重新执行黑客。它由以下几行组成:

#
# The #!/bin/sh might be some legacy piece of crap,
# not even up to 1990 POSIX.2 spec. So the first step
# is to look for a better shell in some known places
# and re-execute ourselves with that interpreter.
#

if test x$txr_shell = x ; then
  for shell in /bin/bash /usr/bin/bash /usr/xpg4/bin/sh ; do
    if test -x $shell ; then
       txr_shell=$shell
       break
    fi
  done
  if test x$txr_shell = x ; then
    echo "No known POSIX shell found: falling back on /bin/sh, which may not work"
    txr_shell=/bin/sh
  fi
  export txr_shell
  exec $txr_shell $0 ${@+"$@"}
fi

txr_shell 变量(不是标准变量,我的发明)是该逻辑检测到它已被重新执行的方式。如果变量不存在,那么这是原始执行。当我们重新执行时,我们 export txr_shell 因此重新执行的实例将具有此环境变量。

该变量还保存了shell的路径;稍后在脚本中使用;它作为SHELL 变量传递给Makefile,以便构建配方使用相同的shell。在上述逻辑中,txr_shell 的内容无关紧要;它用作布尔值:它存在或不存在。

上面代码 sn-p 中的编程风格是故意编码为在非常旧的 shell 上工作。这就是为什么使用test x$txr_shell = x 而不是现代语法[ -z "$txr_shell" ],以及为什么使用${@+"$@"} 而不仅仅是"$@"

在脚本中的这一点之后不再使用这种样式,因为 多亏了重新执行的技巧,脚本的其余部分可以在一些不错的、相当现代的 shell 中运行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-11
    • 2020-04-02
    • 1970-01-01
    • 1970-01-01
    • 2014-04-07
    • 2011-07-19
    • 2015-03-01
    相关资源
    最近更新 更多