为什么 bash 中作为命令 (::) 的两个冒号的错误消息有三个冒号,而单个冒号没有输出?

Ner*_*nux 27 command-line bash

如果我输入

::
Run Code Online (Sandbox Code Playgroud)

进入 bash shell,我得到:

-bash: ::: command not found
Run Code Online (Sandbox Code Playgroud)

但是,只有一个:导致没有输出。为什么是这样?

ste*_*ver 54

最后一个冒号只是默认“未找到”消息的一部分:

$ x
x: command not found
$ ::
::: command not found
Run Code Online (Sandbox Code Playgroud)

单个冒号什么也不产生的原因是它: 一个有效的命令 - 尽管它什么都不做(除了 return TRUE)。从SHELL BUILTIN COMMANDS部分man bash

   : [arguments]
          No effect; the command does nothing beyond  expanding  arguments
          and  performing any specified redirections.  A zero exit code is
          returned.
Run Code Online (Sandbox Code Playgroud)

你有时会在像这样的结构中看到它

while :
do
  something
done
Run Code Online (Sandbox Code Playgroud)

例如,请参阅冒号内置函数的用途是什么?


Ser*_*nyy 40

:壳内置VS不存在::

所述: 壳内置命令存在(注意之间差外部和内置命令),其不执行任何操作; 它只是返回成功,就像true命令一样。在:内置的是标准的,由POSIX标准定义,它也被称为“零效用”。它经常用于测试或运行无限循环,如while : ; do ...;done

bash-4.3$ type :
: is a shell builtin
Run Code Online (Sandbox Code Playgroud)

但是,::- 两个冒号字符一起 - 被解释为外壳的一个“单词”,并且它假定是用户输入的命令。shell 将检查内置PATH命令,然后检查变量中的任何目录是否存在该命令。但是既没有内置:: 命令也没有外部命令::。因此,这会产生错误。

那么,错误的典型格式是什么?

<shell>: <command user typed>: error message
Run Code Online (Sandbox Code Playgroud)

因此,您看到的不是 3 个冒号,而是您输入的粘贴到标准错误格式的内容。

另请注意,这:可以采用命令行参数,即这样做是合法的:

: :
Run Code Online (Sandbox Code Playgroud)

在这种情况下,shell 会将其视为两个“词”,其中一个是命令,另一个是位置参数。这也不会产生错误!(另请参阅有关使用 of:和位置参数的历史注释(在本答案后面)。)


在 bash 以外的 shell 中

请注意,不同外壳之间的格式也可能有所不同。对于bashkshmksh行为是一致的。例如,Ubuntu 的默认/bin/shshell(实际上是/bin/dash):

$ dash
$ ::
dash: 1: ::: not found
Run Code Online (Sandbox Code Playgroud)

其中 1 是命令号(相当于脚本中的行号)。

csh 相比之下,根本不会产生任何错误消息:

$ csh
% ::
%
Run Code Online (Sandbox Code Playgroud)

事实上,如果您运行strace -o csh.trace csh -c ::csh.trace文件中的跟踪输出显示csh退出状态为 0(无错误)。但tcsh确实输出错误(虽然不输出其名称):

$ tcsh
localhost:~> ::
::: Command not found.
Run Code Online (Sandbox Code Playgroud)

错误信息

通常,错误消息中的第一项应该是正在执行的进程或函数(您的 shell 尝试执行::,因此错误消息来自 shell)。例如,这里的执行过程是stat

$ stat noexist
stat: cannot stat 'noexist': No such file or directory
Run Code Online (Sandbox Code Playgroud)

事实上,POSIX 定义了perror()函数,根据文档,它接受一个字符串参数,然后在冒号后输出错误信息,然后是换行符。引用:

perror() 函数应将通过符号 errno 访问的错误号映射到与语言相关的错误消息,该消息应按如下方式写入标准错误流:

  • 首先(如果 s 不是空指针并且 s 指向的字符不是空字节),则 s 指向的字符串后跟一个冒号和一个 <space>。

  • 然后是一个错误消息字符串,后跟一个 <newline>。

perror()技术上讲,字符串参数可以是任何东西,但当然为了清楚起见,它通常是函数名称或argv[0].

相比之下, GNU 有自己的一组用于错误处理的函数和变量,程序员可以使用它们来fprintf()进行stderr流式处理。正如链接页面上的示例之一所示,可以执行以下操作:

  fprintf (stderr, "%s: Couldn't open file %s; %s\n",
           program_invocation_short_name, name, strerror (errno));
Run Code Online (Sandbox Code Playgroud)

历史记录

在旧的 Unix 和 Thompson shell 中,:使用 withgoto语句(根据该线程上名为 Perderabo 的用户的说法,不是内置的 shell)。引用手册:

在整个命令文件中搜索以 : 作为第一个非空白字符开头的行,然后是一个或多个空格,然后是标签。如果找到这样的行,goto 将命令文件偏移重新定位到标签后的行并退出。这会导致外壳转移到标记线。

所以你可以做这样的事情来制作一个无限循环脚本:

: repeat
echo "Hello World"
goto repeat
Run Code Online (Sandbox Code Playgroud)


Olo*_*rin 8

尝试任何其他不存在的命令,您将看到该命令:以英语提供正常用途:

$ ---
---: command not found
Run Code Online (Sandbox Code Playgroud)


小智 6

$ ::
bash: ::: command not found
$ kkkk
bash: kkkk: command not found
Run Code Online (Sandbox Code Playgroud)

第三个是格式化的间隔

在 bash a:是一个空行 void 指令


Joh*_*ion 6

添加的冒号是错误消息本身的一部分。如果一种类型的cd ow结果为bash: cd: ow: No such file or directory,则表明错误是在额外的冒号中: No such file or directory