Bash文件扩展名是什么?

126

我在文本编辑器中编写了一个bash脚本,应该以什么扩展名保存我的脚本,才能将其作为bash脚本运行? 我创建了一个理论上应该启动ssh服务器的脚本。我想知道如何让脚本在我单击它时执行。我正在运行OS X 10.9.5。


5
Shell脚本不需要特定的扩展名。只需执行bash myscript即可。 - anubhava
14
通常是以.sh为扩展名,但并不一定需要存在扩展名。Linux与Windows不同。用来解释脚本的程序需要在其第一行中指定,应该写成 #!/bin/bash,甚至可以包含参数。 - Havenard
2
@Amedeo,这将在你的文件中添加一行 #!/bin/bash - Havenard
5
不要使用扩展名:命令名称扩展被视为有害 - gniourf_gniourf
1
这个问题实际上是关于在macOS中执行bash脚本的,但标题或标签中没有任何提示?! - Matthias
显示剩余5条评论
5个回答

148
不同意其他答案,有一个常见的约定是使用.sh扩展名来表示shell脚本,但这个约定并不实用。最好根本不使用扩展名。通过文件名来判断foo.sh是一个shell脚本的优势很小,而且你要为此付出灵活性的损失。
要使bash脚本可执行,它需要在顶部有一个shebang行。
#!/bin/bash

使用chmod +x命令,使系统将其识别为可执行文件。然后,需要将其安装在列在$PATH中的一个目录中。如果脚本名为foo,则可以在shell提示符下键入foo来执行它。或者,如果它位于当前目录中(临时脚本常见),可以键入./foo
(shebang行的另一种形式是:)
#!/usr/bin/env bash

但是请参考this answer以了解利弊的讨论。
无论是shell还是操作系统都不会关注文件名的扩展部分。它只是名称的一部分。而且通过不给它一个特殊的扩展名,你确保任何使用它的人(无论是用户还是其他脚本)都不需要关心它是如何实现的,无论它是一个shell脚本(sh、bash、csh或其他),还是一个Perl、Python或Awk脚本,或者是一个二进制可执行文件。系统专门设计成这样,可以在不知道或不关心其实现方式的情况下调用解释脚本或二进制可执行文件。
类UNIX系统最初只有纯文本的命令行界面。后来添加了像KDE和Gnome这样的图形用户界面。在图形用户界面桌面系统中,你通常可以通过双击引用它的图标来运行一个程序(无论是脚本还是二进制可执行文件)。通常这会丢弃程序可能打印的任何输出,并且不允许传递命令行参数;它比从shell提示符运行要不灵活得多。但对于一些程序(主要是图形用户界面客户端),这可能更方便。
Shell脚本最好从命令行学习,而不是从图形用户界面学习。
(有些工具确实会注意文件扩展名。例如,编译器通常使用扩展名来确定代码所使用的语言:.c表示C语言,.cpp表示C++等。但这种约定不适用于可执行文件。)
请记住,UNIX(以及类UNIX系统)与Windows不同。MS Windows通常使用文件的扩展名来确定如何打开/执行它。二进制可执行文件需要具有.exe扩展名。如果在Windows下安装了类UNIX的shell,您可以配置Windows识别.sh扩展名作为shell脚本,并使用shell来打开它;Windows没有#!约定。

3
我所追求的是你在第四段提到的。当点击与之相关的图标时,运行我的脚本。 - Amedeo
3
@Amedeo: 那就要看你的桌面环境了。在我使用的那个(Ubuntu下的Cinnamon),双击可执行脚本的图标会提示我在终端中运行它,将其显示在编辑器中,或者在没有终端的情况下运行它。这样做与文件扩展名无关。 - Keith Thompson
10
如果你省略文件扩展名,就不能有同名的文件夹了。例如,如果你有一个名为deploy.sh(或deploy.bash)的脚本和一个名为deploy的文件夹,其中包含其他的部署逻辑。如果你将脚本重命名为deploy,它将导致名称冲突。给文件或文件夹命名不同的名称会影响可管理性和可能导致文件排序(如在编辑器中输入ls等命令)。当然,shebang最终是决定性因素。但是文件扩展名确实有其合理的位置。 - Kafoso
3
@Kafoso说:“我从来没有感觉需要用同样的名字来命名脚本和目录。如果我必须这样做,我可能会把目录叫做Deploy,但是当复制到不区分大小写的文件系统时可能会出现问题。” - Keith Thompson
3
在 Mac 上,双击文件会 总是 用默认应用程序打开它们。因此,将脚本文件命名为 .sh 扩展名可以让它在你想要的编辑器中打开。如果你想在双击时运行一个脚本,给它命名为 .command 扩展名,这样它就会在终端中运行。 - BallpointBen
显示剩余3条评论

26
你不需要任何扩展名(或者你可以选择任意一个,但是.sh是一个有用的约定)。你应该以#!/bin/bash开头(这行代码被execve(2)系统调用理解),并且你应该将你的文件设置为可执行文件 chmod u+x。因此,如果你的脚本在文件$HOME/somedir/somescriptname.sh中,你只需键入一次命令即可。
 chmod u+x  $HOME/somedir/somescriptname.sh
在终端中执行脚本可以使用 chmod(1) 命令或系统调用 chmod(2),除非要输入完整的文件路径,否则应该将文件放在 PATH 中提到的某个目录中(参见 environ(7)execvp(3)),如果您的登录 shell 是 bash,可以将其永久设置在 ~/.bashrc 中。

顺便说一下,您可以使用其他语言编写脚本,例如以#!/usr/bin/python开头的 Python 脚本,或以#!/usr/bin/ocaml开头的 Ocaml 脚本...

通过双击执行脚本是桌面环境的问题,可能与桌面有关(Kde、Mate、Gnome、IceWM 或 RatPoison 等可能不同)。阅读EWMH规范可能会有所帮助。

也许使用 chmod 命令将脚本设为可执行文件,就可以在桌面上点击运行(显然,在 MacOSX 上是 Quartz)。但是,您可能应该让它给出一些视觉反馈。

然而有一些计算机没有桌面环境,包括您通过 ssh 远程访问自己的计算机时。

我认为不建议通过双击运行您的 shell 脚本。您可能想要能够向脚本传递参数(如何通过单击实现这一点?),并且应该关注其输出。如果您能编写 shell 脚本,则能够在终端中使用交互式 shell。这是使用脚本的最佳和最自然的方式。良好的交互式 shell(例如 zshfish 或最近的bash)具有美味且可配置的自动完成功能,您不必输入太多内容(学会使用键盘的 tab 键)。此外,脚本和程序通常是复合命令(管道等)的一部分。

PS。我自 1986 年以来使用 Unix,自 1993 年以来使用 Linux。我从未通过单击启动过自己的程序或脚本。为什么我要那样做呢?


4
好的,我已经在文本编辑器中创建了我的脚本。我将文件保存到桌面上。当我单击保存在桌面上的脚本时,我希望它能够在我单击它时实际运行。 - Amedeo
6
我不知道你的桌面环境是什么(KDE,Gnome,MATE等)。我强烈建议你在终端中使用命令行,尤其是运行脚本时(你可能想给它们一些参数; 在桌面环境上该如何做?)。如果你能编写一个shell脚本,你就应该能够在终端中交互地使用shell。 - Basile Starynkevitch
3
我明白了,这是我正在处理的一个项目。我希望当点击时能够执行脚本,避免使用终端来运行脚本。 - Amedeo
2
再次阅读您的答案后,我非常明白应该通过终端运行bash脚本,但这不是重点。我不再试图找到运行bash脚本的方法。我特别询问是否可以通过单击它们来运行脚本(为我正在进行的项目),并且在脚本中,我不要求输出任何内容。我只想通过单击脚本来执行我编写的命令。没有任何图形需要出现。 - Amedeo
3
除非有特定的原因需要限制只有文件所有者才能执行,否则我会使用chmod +x而不是chmod u+x - Keith Thompson
显示剩余15条评论

7

仅需要 .sh 文件。

按照以下方式运行脚本:

./script.sh

编辑:就像anubhava所说的,扩展名并不是特别重要。但出于组织原因,仍然建议使用扩展名。


7
如果您运行脚本,一般来说您不需要关心它是用什么语言编写的。Bash 脚本和二进制可执行文件都是以相同的方式执行的。给可执行脚本添加 .sh 后缀通常只会增加无用的混乱。 - Keith Thompson
3
是的,但正如我在编辑中所说的那样,这只是一种组织脚本的惯例 - 没有更多的意思吗?! - Marc Anton Dahmen
6
我看到很多脚本使用.sh扩展名(.bash的使用较少),但我并不认为这样做有任何用处。如果我将一个脚本命名为foo.sh,然后决定用Perl重新实现它,我可以要么更改名称(并编辑所有使用该名称的地方),要么让其带有误导性的扩展名。如果我将其命名为foo,就不会有这个问题。 - Keith Thompson
1
@KeithThompson 我可以想到一个用途,我*确实关心脚本是用什么语言编写的。我不能代表Perl说话,但如果脚本是用Python或Bash编写的,我会非常在意。我通常可以假设Bash脚本无论如何都能工作,但Python脚本有依赖性,并且Python 2和Python 3彼此不兼容。我还认为区分编译后的二进制文件和脚本(两者都没有扩展名)很重要,因为它们具有不同的依赖需求(例如,二进制文件可能需要库并针对AMD64进行编译,只能在该平台上运行)。 - jrh
2
@jrh 当然,有时候这很重要(你可以通过运行 head -1 script.foofile script.foo 来判断)。但是如果一切都安装和配置正确,99% 的时间我只想让命令执行它应该执行的操作。对我来说,这并不意味着每次运行命令都必须知道 .py.bash 后缀。 - Keith Thompson

2

我知道这已经很老了,但我觉得这对问题的提问有所补充。

如果你使用的是Mac,并且想通过双击运行脚本,你需要使用.command扩展名。同样,像之前一样,使用chmod -x使文件可执行。

正如之前所述,实际上这并不是非常有用。


1

简而言之 -- 如果脚本的用户(不一定是开发者)使用GUI界面,则取决于他们使用的文件浏览器。在MacOS的Finder中,需要.sh扩展名才能执行脚本。然而,Gnome Nautilus可以正确识别有或没有.sh扩展名的脚本。

我知道已经多次说过使用扩展名的优缺点,但为什么使用或不使用扩展名却没有那么多人讨论,我认为有一个好的经验法则。

如果你是那种经常在终端和bash中切换或正在为不使用终端的其他人开发工具的人,请在你的bash脚本中加上.sh扩展名。这样,该脚本的用户可以选择在GUI文件浏览器中双击该文件来运行脚本。

如果你是那种主要在终端中完成所有或大部分工作的人,请不要在你的bash脚本中加任何扩展名。假设你已经设置好了~/.bashrc文件以在视觉上区分脚本和目录,它们在终端中将毫无用处。

编辑:

在Gnome Nautilus文件浏览器中,有4个测试文件(每个文件都有执行权限),使用非常简单的bash命令打开终端窗口(gnome-terminal):
  1. 第一行为#!/bin/bash,没有扩展名的文件。

    双击该文件即可运行。

  2. 第一行为#!/bin/bash,扩展名为.sh的文件。

    双击该文件即可运行。

  3. 没有扩展名,第一行没有#!/bin/bash的文件。

    双击该文件可以运行,但GUI没有指示它是一个shell脚本,而是显示为纯文本文件。

  4. 扩展名为.sh,第一行没有#!/bin/bash的文件。

    双击该文件即可运行。

然而,正如Keith Thompson在本答案的评论中明智地指出的那样,仅依赖于使用.sh扩展名而不是文件的第一行(#!/bin/bash)上的bash shebang可能会引起问题。
另外,我还记得以前使用MacOS时,即使正确地使用了shebang(这是一个单词吗?)bash脚本,没有.sh扩展名也无法从GUI上运行。但如果有人能在评论中纠正我,我将不胜感激。如果这是真的,那么就证明至少有一个文件浏览器在这里.sh扩展名很重要。

你使用哪个GUI文件浏览器(或者更相关的是,你的用户使用什么)?它是否使用扩展名来决定如何运行脚本? - Keith Thompson
嗯,我最有经验的平台是MacOS。在Finder中,用户可以决定将哪些应用程序与哪个扩展名关联起来。 现在,我正在使用Gnome的Linux,但我还没有尝试过Gnome的Nautilus文件浏览器如何与没有扩展名的文件交互。 - Ryan Hart
如果您有一个以.sh为后缀,并且第一行有#!/bin/bash的可执行脚本,那么GUI文件浏览器是否会使用sh来调用它(忽略shebang)?如果是这样,将会引起一些问题。(不同的浏览器的答案可能不同。) - Keith Thompson
那里有很好的观点。我刚刚进行了一些实际测试,现在已经更新了我的答案。 - Ryan Hart
问题是,如果脚本的名称带有.sh后缀,GUI会使用/bin/sh还是/bin/bash来执行它?如果它使用bash特定的功能并且使用/bin/sh调用它,那么它可能会出现错误。如果GUI注意到了shebang,你可以有一个名为foo.sh的Perl脚本。为什么要以两种不一致的方式指定解释器呢? - Keith Thompson
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接