使用点空间与点斜杠执行文件

TTT*_*TTT 20 linux bash shell ksh operators

我正在尝试使用现有的代码库但遇到了问题.简而言之,我执行一个shell脚本(让我们称之为这个A),其第一步是调用另一个脚本(B).脚本B在我当前的目录中(我正在使用的程序的要求).该软件的手册参考了bash,但是评论A表明它是在开发的ksh.bash到目前为止我一直在经营.

在内部A,要执行的行B是:

. B
Run Code Online (Sandbox Code Playgroud)

它使用"点空间"语法来调用程序.它没有做任何不寻常的事情sudo.

当我在A没有点空格语法的情况下调用时,即:

./A
Run Code Online (Sandbox Code Playgroud)

它总是错误,说它找不到文件B.我说pwd,ls,whoami,echo $SHELL,和echo $PATH线A调试和确认,B实际上是在那里,脚本与相同的运行$SHELL,因为我在命令提示符下,脚本是相同的用户,因为我,和脚本有$PATH和我一样的搜索路径.我还验证了我是否这样做:

. B
Run Code Online (Sandbox Code Playgroud)

在命令行,它工作得很好.但是,如果我将内部语法更改A为:

./B
Run Code Online (Sandbox Code Playgroud)

相反,然后A成功执行.

同样,如果我执行A与点空间句法,那么这两个. B./B工作.

总结:
./A仅在A包含./B语法时才有效.
. A适用于A任何一种./B. B语法.

我知道使用点空间(即. A)语法执行而不会分支到子shell,但我不知道这是如何导致我观察到的行为,因为文件显然是正确的.对于语法或父/子进程工作空间的细微差别,我有什么遗漏吗?魔法?

UPDATE1:ksh在我使用时添加了表明脚本可能已经开发的信息bash.
UPDATE2:添加检查验证$PATH是否相同.

UPDATE3:脚本说它是为它编写的ksh,但它正在运行bash.为了响应Kenster的答案,我发现,运行bash -posix,然后. B在命令行失败.这表明命令行和脚本之间的环境差异是后者bash在POSIX兼容模式下运行,而命令行则不是.仔细观察,我在bash man页面中看到了这一点:

当调用为sh时,bash在读取启动文件后进入posix模式.

shebangA确实是#!/bin/sh.

总而言之,当我在A没有点空间语法的情况下运行时,它正在分支它自己的子shell,它处于POSIX兼容模式,因为它shebang#!/bin/sh(而不是,例如,#!/bin/bash.这是命令行和脚本运行时环境之间的关键差异,导致对A暂时无法找到B.

Ken*_*ter 27

让我们从命令路径的工作原理和使用时间开始.当您运行如下命令时:

ls /tmp
Run Code Online (Sandbox Code Playgroud)

ls这里不包含/字符,所以壳在搜索命令路径中的目录(PATH环境变量的值)命名的文件ls.如果找到一个,则执行该文件.在这种情况下ls,它通常在/bin/usr/bin,并且这两个目录通常都在您的路径中.

在命令字中使用/发出命令时:

/bin/ls /tmp
Run Code Online (Sandbox Code Playgroud)

shell不搜索命令路径.它专门查找文件/bin/ls并执行它.

运行./A是运行名称中包含/的命令的示例.shell不搜索命令路径; 它专门查找名为的文件./A并执行它."" 是当前工作目录的简写,因此./A指的是应该在当前工作目录中的文件.如果文件存在,它就像任何其他命令一样运行.例如:

cd /bin
./ls
Run Code Online (Sandbox Code Playgroud)

会努力运行/bin/ls.

运行. A获取文件的示例.源文件必须是包含shell命令的文本文件.它由当前shell执行,无需启动新进程.找到源文件的方式与找到命令的方式相同.如果文件名包含/,则shell将读取您指定的特定文件.如果文件名不包含/,则shell在命令路径中查找它.

. A        # Looks for A using the command path, so might source /bin/A for example
. ./A      # Specifically sources ./A
Run Code Online (Sandbox Code Playgroud)

因此,您的脚本会尝试执行. B并且无法声明B不存在,即使B当前目录中有一个名为right 的文件.如上所述,shell将搜索您的命令路径,B因为它B不包含任何/字符.搜索命令时,shell不会自动搜索当前目录.它仅搜索当前目录,如果该目录是命令路径的一部分.

简而言之,. B可能是失败的,因为你没有"." 您的命令路径中的(当前目录),并且尝试源的脚本B假定为"." 是你的道路的一部分.在我看来,这是脚本中的一个错误.很多人没有".".在他们的道路上,脚本不应该依赖于此.

编辑:

你说ksh在你使用时脚本使用了bash.Ksh遵循POSIX标准 - 实际上,KSH是POSIX标准的基础 - 并且总是按照我的描述搜索命令路径.Bash有一个名为"POSIX模式"的标志,它控制它遵循POSIX标准的严格程度.当不处于POSIX模式时 - 人们通常使用它 - 如果在命令路径中找不到该文件,bash将检查当前目录中是否有源文件.

如果您要在该bash实例中运行bash -posix并运行. B,您应该会发现它不起作用.

  • 也许还可以解释说,在当前进程中获取文件意味着源文件可以操纵您的环境。因此,如果您运行`。B和B执行foo = bar之后,将在B完成后设置此变量,直到当前脚本或交互式shell退出,而./A无法更改变量(子进程无法更改其父级)。 (2认同)