为什么我的 shell 脚本在没有 .sh 扩展名的情况下会挂起?

为什么我的 shell 脚本在没有 .sh 扩展名的情况下会挂起?

我创建了一个shell脚本/usr/local/bin/suspend,内容如下:

#! /bin/sh

# Take an optional delay parameter
if [ "$#" -gt "0" ]; then
  sleep "$1"
fi

# Put the system to sleep
dbus-send --system --print-reply --dest="org.freedesktop.Hal" \
    /org/freedesktop/Hal/devices/computer \
    org.freedesktop.Hal.Device.SystemPowerManagement.Suspend \
    int32:0

如果我chmod +x通过直接调用来运行该脚本(例如,只需在命令行上键入suspend或),则什么也不会发生,并且 shell 会挂起 - 它甚至不会响应 Ctrl-C;我必须切换到新的 shell 并终止该进程(该进程没有明显的子进程)。/usr/local/bin/suspendbash

如果我以以下任何一种方式调用该脚本,它都可以正常工作:

  • 使用sh /usr/local/bin/suspend
  • 使用. /usr/local/bin/suspend
  • 将其重命名为suspend.sh并调用/usr/local/bin/suspend.sh(或者只是suspend.sh,因为它在 中PATH)。

最后一个选项很好,但我仍然想知道:不使用扩展到底有什么问题.sh

答案1

suspend是 bash 的内置命令,

suspend: suspend [-f]
Suspend shell execution.

Suspend the execution of this shell until it receives a SIGCONT signal.
Unless forced, login shells cannot be suspended.

Options:
  -f    force the suspend, even if the shell is a login shell

Exit Status:
Returns success unless job control is not enabled or an error occurs.

并且由于内置命令优先,只需键入suspend即可完全按照您描述的方式运行:shell 会阻塞,直到您将其杀死(如果您kill -CONT杀死它,它会恢复)。

通过使用路径调用它,您会看到同样的行为,这可能是实验错误,也可能是 shell 中的错误。我怀疑是前者,而不是后者。

答案2

如果您希望您的命令取代内置命令,您首先必须禁用内置命令:

enable -n suspend

然后,您可以像普通命令一样运行命令。然后,重新启用内置

enable suspend

我很惊讶当您使用完整路径调用命令时内置函数会被调用。

答案3

回答您关于 sh 扩展的问题;事实恰恰相反,您不应该使用它。

不要为脚本使用扩展名。脚本定义了你可以运行的新命令,而命令通常没有扩展名。另外:bash 脚本是不是sh 脚本(所以不要使用 .sh)并且扩展只在用另一种语言重写脚本时才会引起依赖性问题。

Freenode.net 上的 #bash

相关内容