为什么有些系统.sh
只需指定文件名而不指定扩展名即可运行文件,而其他系统则需要名称加扩展名? 就我而言,我尝试按照这些命令编写一系列命令指示。
我现在正在指定扩展,但如果能够在没有扩展的情况下运行命令.sh
就更好了。
答案1
您搞糊涂了。.sh
扩展名只是对人类的一个提示,对系统处理文件的方式完全没有影响。Unix/Linux 没有犯下 Windows 的Secrets.pdf.exe
错误。
当您输入以下内容时,将发生以下情况foo
:
已设置
STDIN
、STDOUT
和的重定向。STDERR
shell 检查其内部哈希表,查看是否已经知道 的
$PATH
条目foo
。如果不存在,shell 会搜索 中的目录$PATH
,查找名为 且foo
在其文件权限中设置了执行位的文件。先到foo
先得。如果文件的前两个字节
foo
是#!
,则下一个字符串是要运行的解释器的名称。因此#!/bin/bash
引入了一个 Bash 脚本,#!/usr/bin/perl
引入了一个 Perl 脚本,等等。如果文件以 开头
\177ELF
,则它是二进制可执行文件,并ld.so
启动它。
阅读man execve
并man ld.so
获得更详细的解释。
答案2
关键点是这样的:扩展名在任何类 Unix 系统中都是无关紧要的。文件名只是名称,对脚本或编译后的可执行文件是否可以运行没有影响。程序员可以添加.sh
扩展名来表明某个文件是 shell 脚本,或者.py
是 python 脚本,但与 Windows 不同,任何 unix 都不关心命名,它只关心权限。
重要的是授予文件的可执行权限。您可以使用以下命令进行检查
ls -l /path/to/file
运行可执行文件
运行脚本一般有几种方法。
- 如果您的当前目录与脚本相同,并且脚本具有可执行权限,则可以像这样运行它
./my_script_name
。.
表示当前目录。 - 如果您的当前目录不同并且脚本具有可执行权限,则可以通过指定完整路径来运行它:
/home/user/bin/my_script_name
(以上两种方法依赖于设置可执行权限;文件是否是$PATH
变量的一部分无关紧要。#!
行的存在也很重要;如果没有它,脚本将由您打开的当前 shell 执行。如果我的csh
脚本没有该行,并尝试在 bash 中使用运行它./my_script.csh
,它将失败)
- 如果您的脚本位于属于
$PATH
变量的目录中,则只需调用名称即可运行它。您chmod
只需在命令行中输入其名称即可调用命令,因为它位于/bin
文件夹中。/bin
始终是$PATH
变量的一部分。在这种情况下,可执行权限和脚本的位置很重要 - 指定解释器作为命令,脚本作为参数。这样,脚本将作为解释器的输入文件。
- 获取文件。
. filename.sh
或source filename.sh
将使脚本被视为键盘输入,即直接输入命令行。在这种情况下,可执行权限和位置无关紧要
例子
示例 #1,使用解释器运行,以执行权限
$-> ls -l abc.py
-rw-rw-r-- 1 xieerqi xieerqi 44 Apr 27 22:39 abc.py
$-> python abc.py
a
b
c
示例#2,使用./
可执行权限集和shebang 行集运行。
$-> cat abc.py
#!/usr/bin/env python
for letter in 'a' 'b' 'c' :
print letter
$-> ls -l abc.py
-rwxrwxr-x 1 xieerqi xieerqi 66 Apr 27 23:02 abc.py*
$-> ./abc.py
a
b
c
示例 #3,未设置 shebang 行的情况下运行(失败,因为 bash 无法读取 python 脚本;没有 shebang 行假定当前 shell 作为解释器)
$-> cat abc.py
for letter in 'a' 'b' 'c' :
print letter
$-> ./abc.py
./abc.py: 2: ./abc.py: Syntax error: word unexpected (expecting "do")
示例 #4,运行具有可执行权限的脚本,该权限设置来自$PATH
变量的一部分文件夹
# /home/xieerqi/bin is part of my path variable
$-> echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/opt/microchip/xc16/v1.25/bin:/opt/microchip/xc32/v1.40/bin:/opt/microchip/xc8/v1.35/bin:/home/xieerqi/bin:/home/xieerqi/bin/sh
$-> # current directory is /home/xieerqi
$-> pwd
/home/xieerqi
$-> # move the file to ~/bin
$-> mv ~/abc.py ~/bin/abc.py
$-> # now I can run it just by calling the name
$-> abc.py
/home/xieerqi/bin/abc.py: 2: /home/xieerqi/bin/abc.py: Syntax error: word unexpected (expecting "do")
$-> # Syntax error because again, no interpreter specified.
$-> # must add #!/usr/bin/env python
$-> vi /home/xieerqi/bin/abc.py
$-> # after adding the line with vi text editor, we can run
$-> abc.py
a
b
c
示例#5,删除扩展,仍然可以运行,因为扩展并不重要,但它具有权限并且是其中的一部分$PATH
:
$-> mv ~/bin/abc.py ~/bin/abc
$-> abc
a
b
c
答案3
这里已经有很好的解释。我只是想补充一点,理想情况下你不应该对可执行文件使用文件扩展名。
通常你需要完成一些相对简单的事情,并且从一个小的 shell 脚本开始。随着时间的推移,你开始向脚本添加越来越多的功能,直到它变得无法维护,或者你需要一些无法用 shell 脚本轻松实现的功能,并考虑用另一种语言(python、perl 等?)重写这个 shell 脚本。
从头重写通常被认为是一种错误,但对于脚本来说,这可能是有意义的,因为它们通常不是那么大或具有很多功能。但让我们假设用其他语言从头重写是可行的,同时保留初始 shell 脚本的功能和参数/标志。
该脚本的用户不需要了解这种语言变化,他们将继续执行相同的命令,并且它将继续工作。
如果你的脚本被命名为do-something.sh
,它可以继续存在do-something.sh
,但现在它是用python编写的(例如),所以你的初始暗示现在却完全是误导性的。
答案4
.sh 后缀实际上会造成问题,因为要运行它,您必须键入 myscript.sh,而不是只键入 myscript,因为这样是行不通的。最好直接将其命名为“myscript”,而不使用 .sh 后缀,然后快速使用“file”命令即可知道它是二进制可执行文件(Linux 上的 ELF 格式)还是 shell 脚本,或者任何其他类型的脚本。
QDOS(Quick and Dirty 操作系统,后来被 IBM 更名为“DOS”,因为微软盗版并非法将其出售给他们)和其他廉价的 CP/M 仿制品,包括 Windows,将所有这些都混为一谈,因为在这些系统上没有文件执行权限。这在过去 30-40 年里导致了无数的安全问题。实际上,就在几分钟前,我收到了几封垃圾邮件,里面有一个被重命名为 MYPICTURE.JPG.zip 的陷阱 zip 文件 :)