bash 点空间与点斜线的文件执行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24290726/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
File execution with dot space versus dot slash
提问by TTT
I am attempting to work with an existing library of code but have encountered an issue. In short, I execute a shell script (let's call this one A
) whose first actis to call another script (B
). Script B
is in my current directory (a requirement of the program I'm using). The software's manual makes reference to bash
, however comments in A
suggest it was developed in ksh
. I've been operating in bash
so far.
我正在尝试使用现有的代码库,但遇到了问题。简而言之,我执行了一个 shell 脚本(我们称之为这个脚本A
),它的第一个动作是调用另一个脚本 ( B
)。脚本B
在我的当前目录中(我正在使用的程序的要求)。该软件的手册参考了bash
,但是中的评论A
表明它是在ksh
. bash
到目前为止,我一直在运营。
Inside A
, the line to execute B
is simply:
在里面A
,要执行的行B
很简单:
. B
It uses the "dot space" syntax to call the program. It doesn't do anything unusual like sudo
.
它使用“点空间”语法来调用程序。它不会做任何不寻常的事情,比如sudo
.
When I call A
without dot space syntax, i.e.:
当我在A
没有点空间语法的情况下调用时,即:
./A
it always errors saying it cannot find the file B
. I added pwd
, ls
, whoami
, echo $SHELL
, and echo $PATH
lines to A
to debug and confirmed that B
is in fact right there, the script is running with the same $SHELL
as I am at the command prompt, the script is the same user as I am, and the script has the same search path $PATH
as I do. I also verified if I do:
它总是错误说它找不到文件B
。我添加了pwd
, ls
, whoami
,echo $SHELL
和echo $PATH
行来A
调试并确认B
实际上就在那里,脚本的运行方式与$SHELL
我在命令提示符下的运行方式相同,脚本与我的用户相同,并且脚本具有$PATH
和我一样的搜索路径。我还验证了我是否这样做:
. B
at the command line, it works just fine. But, if I change the syntax inside A
to:
在命令行,它工作得很好。但是,如果我将里面的语法更改A
为:
./B
instead, then A
executes successfully.
相反,然后A
成功执行。
Similarly, if I execute A
with dot space syntax, then both . B
and ./B
work.
同样,如果我执行A
与点空间句法,那么这两个. B
和./B
工作。
Summarizing:./A
only works if A
contains ./B
syntax.. A
works for A
with either ./B
or . B
syntax.
总结:./A
仅在A
包含./B
语法时才有效。. A
适用于A
有两种./B
或. B
语法。
I understand that using dot space (i.e. . A
) syntax executes without forking to a subshell, but I don't see how this could result in the behavior I'm observing given that the file is clearly right there. Is there something I'm missing about the nuances of syntax or parent/child process workspaces? Magic?
我知道使用点空间(即. A
)语法在不分叉到子shell 的情况下执行,但我不明白这会如何导致我观察到的行为,因为文件显然就在那里。关于语法或父/子进程工作区的细微差别,我是否遗漏了什么?魔法?
UPDATE1: Added info indicating that the script may have been developed in ksh
, while I'm using bash
.
UPDATE2: Added checking to verify $PATH
is the same.
UPDATE1:添加的信息表明脚本可能是在 中开发的ksh
,而我正在使用bash
.
UPDATE2:添加检查以验证$PATH
是否相同。
UPDATE3: The script says it was written for ksh
, but it is running in bash
. In response to Kenster's answer, I found that running bash -posix
then . B
fails at the command line. That indicates that the difference in environments between the command line and the script is that the latter is running bash
in a POSIX-compliant mode, whereas the command line is not. Looking a little closer, I see this in the bash
man
page:
UPDATE3:脚本说它是为 编写的ksh
,但它正在bash
. 针对 Kenster 的回答,我发现在命令行中运行bash -posix
然后. B
失败。这表明命令行和脚本之间的环境差异在于后者bash
以符合 POSIX 的模式运行,而命令行则不是。靠近一点,我在bash
man
页面中看到了这个:
When invoked as sh, bash enters posix mode after the startup files are read.
当作为 sh 调用时,bash 在读取启动文件后进入 posix 模式。
The shebang
for A
is indeed #!/bin/sh
.
在shebang
为A
确实是#!/bin/sh
。
In summary, when I run A
without dot space syntax, it's forking to its own subshell, which is in POSIX-compliant mode because the shebang
is #!/bin/sh
(instead of, e.g., #!/bin/bash
. This is the critical difference between the command line and script runtime environments that leads to A
being unable to find B
.
总之,当我在A
没有点空间语法的情况下运行时,它会分叉到它自己的子 shell,它处于 POSIX 兼容模式,因为shebang
是#!/bin/sh
(而不是,例如#!/bin/bash
。这是命令行和脚本运行时环境之间的关键区别,导致到A
无法找到B
。
回答by Kenster
Let's start with how the command path works and when it's used. When you run a command like:
让我们从命令路径的工作原理和使用时间开始。当您运行如下命令时:
ls /tmp
The ls
here doesn't contain a / character, so the shell searches the directories in your command path (the value of the PATH environment variable) for a file named ls
. If it finds one, it executes that file. In the case of ls
, it's usually in /bin
or /usr/bin
, and both of those directories are typically in your path.
在ls
这里不包含/字符,所以shell搜索在一个文件名为您的命令路径(PATH环境变量的值)的目录ls
。如果找到一个,它就会执行那个文件。在 的情况下ls
,它通常在/bin
或 中/usr/bin
,并且这两个目录通常都在您的路径中。
When you issue a command with a / in the command word:
当您在命令字中发出带有 / 的命令时:
/bin/ls /tmp
The shell doesn't search the command path. It looks specifically for the file /bin/ls
and executes that.
shell 不搜索命令路径。它专门查找该文件/bin/ls
并执行该文件。
Running ./A
is an example of running a command with a / in its name. The shell doesn't search the command path; it looks specifically for the file named ./A
and executes that. "." is shorthand for your current working directory, so ./A
refers to a file that ought to be in your current working directory. If the file exists, it's run like any other command. For example:
运行./A
是运行名称中带有 / 的命令的示例。shell 不搜索命令路径;它专门查找命名的文件./A
并执行该文件。“。” 是当前工作目录的简写,因此./A
指的是应该在当前工作目录中的文件。如果文件存在,它会像任何其他命令一样运行。例如:
cd /bin
./ls
would work to run /bin/ls
.
将工作运行/bin/ls
。
Running . A
is an example of sourcinga file. The file being sourced must be a text file containing shell commands. It is executed by the current shell, without starting a new process. The file to be sourced is found in the same way that commands are found. If the name of the file contains a /, then the shell reads the specific file that you named. If the name of the file doesn't contain a /, then the shell looks for it in the command path.
运行. A
是获取文件的一个示例。源文件必须是包含 shell 命令的文本文件。它由当前 shell 执行,无需启动新进程。要查找的文件的查找方式与查找命令的方式相同。如果文件名包含 /,则 shell 会读取您命名的特定文件。如果文件名不包含 /,则 shell 在命令路径中查找它。
. A # Looks for A using the command path, so might source /bin/A for example
. ./A # Specifically sources ./A
So, your script tries to execute . B
and fails claiming that B
doesn't exist, even though there's a file named B
right there in your current directory. As discussed above, the shell would have searched your command path for B
because B
didn't contain any / characters. When searching for a command, the shell doesn't automatically search the current directory. It only searches the current directory if that directory is part of the command path.
因此,您的脚本尝试执行. B
并失败,声称该脚本B
不存在,即使B
您的当前目录中有一个名为该文件的文件。如上所述,shell 会搜索您的命令路径,B
因为它B
不包含任何 / 字符。搜索命令时,shell 不会自动搜索当前目录。如果该目录是命令路径的一部分,它只会搜索当前目录。
In short, . B
is probably failing because you don't have "." (current directory) in your command path, and the script which is trying to source B
is assuming that "." is part of your path. In my opinion, this is a bug in the script. Lots of people run without "." in their path, and the script shouldn't depend on that.
简而言之,. B
可能会失败,因为您没有“。” (当前目录)在您的命令路径中,并且尝试获取源的脚本B
假设“。” 是你道路的一部分。在我看来,这是脚本中的一个错误。很多人跑的时候没有“。” 在他们的路径中,脚本不应该依赖于此。
Edit:
编辑:
You say the script uses ksh
, while you are using bash
. Ksh follows the POSIX standard--actually, KSH was the basis for the POSIX standard--and always searches the command path as I described. Bash has a flag called "POSIX mode" which controls how strictly it follows the POSIX standard. When not in POSIX mode--which is how people generally use it--bash will check the current directory for the file to be sourced if it doesn't find the file in the command path.
您说脚本使用ksh
,而您正在使用bash
. Ksh 遵循 POSIX 标准——实际上,KSH 是 POSIX 标准的基础——并且总是像我描述的那样搜索命令路径。Bash 有一个称为“POSIX 模式”的标志,用于控制它遵循 POSIX 标准的严格程度。当不在 POSIX 模式下时——这是人们通常使用它的方式——如果在命令路径中没有找到文件,bash 将检查当前目录中要获取的文件。
If you were to run bash -posix
and run . B
within that bash instance, you should find that it won't work.
如果您要在该 bash 实例中运行bash -posix
并运行. B
,您应该会发现它不起作用。