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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 10:42:53  来源:igfitidea点击:

File execution with dot space versus dot slash

linuxbashshelloperatorsksh

提问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 Bis in my current directory (a requirement of the program I'm using). The software's manual makes reference to bash, however comments in Asuggest it was developed in ksh. I've been operating in bashso far.

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

Inside A, the line to execute Bis 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 Awithout 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 $PATHlines to Ato debug and confirmed that Bis in fact right there, the script is running with the same $SHELLas I am at the command prompt, the script is the same user as I am, and the script has the same search path $PATHas I do. I also verified if I do:

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

. B

at the command line, it works just fine. But, if I change the syntax inside Ato:

在命令行,它工作得很好。但是,如果我将里面的语法更改A为:

./B

instead, then Aexecutes successfully.

相反,然后A成功执行。

Similarly, if I execute Awith dot space syntax, then both . Band ./Bwork.

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

Summarizing:
./Aonly works if Acontains ./Bsyntax.
. Aworks for Awith either ./Bor . Bsyntax.

总结
./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 $PATHis 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 -posixthen . Bfails at the command line. That indicates that the difference in environments between the command line and the script is that the latter is running bashin a POSIX-compliant mode, whereas the command line is not. Looking a little closer, I see this in the bashmanpage:

UPDATE3:脚本说它是为 编写的ksh,但它正在bash. 针对 Kenster 的回答,我发现在命令行中运行bash -posix然后. B失败。这表明命令行和脚本之间的环境差异在于后者bash以符合 POSIX 的模式运行,而命令行则不是。靠近一点,我在bashman页面中看到了这个:

When invoked as sh, bash enters posix mode after the startup files are read.

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

The shebangfor Ais indeed #!/bin/sh.

shebangA确实是#!/bin/sh

In summary, when I run Awithout dot space syntax, it's forking to its own subshell, which is in POSIX-compliant mode because the shebangis #!/bin/sh(instead of, e.g., #!/bin/bash. This is the critical difference between the command line and script runtime environments that leads to Abeing 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 lshere 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 /binor /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/lsand executes that.

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

Running ./Ais 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 ./Aand executes that. "." is shorthand for your current working directory, so ./Arefers 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 . Ais 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 . Band fails claiming that Bdoesn't exist, even though there's a file named Bright there in your current directory. As discussed above, the shell would have searched your command path for Bbecause Bdidn'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, . Bis probably failing because you don't have "." (current directory) in your command path, and the script which is trying to source Bis 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 -posixand run . Bwithin that bash instance, you should find that it won't work.

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