checkbashisms:“类型”有什么问题?

pev*_*vik 4 shell shell-builtin

#!/bin/sh

foo() {
   echo "in foo"
}

type foo
Run Code Online (Sandbox Code Playgroud)

checkbashisms.pl明明不喜欢type,为什么?

$ checkbashisms.pl foo.sh
possible bashism in foo.sh line 7(type):
type foo
Run Code Online (Sandbox Code Playgroud)

不是POSIX吗?但是所有常见的外壳都支持它(即bash, zsh, dash, busybox sh, mksh; 甚至在ksh; 也许只是csh不支持它),难道不应该有一种方法来抑制这个警告吗?

Ste*_*itt 11

typePOSIX 的一部分,但作为 X/Open Systems Interfaces 选项 (XSI) 的一部分。checkbashisms手册页明确地说:

请注意,在此上下文中 bashism 的定义大致等同于“POSIX 不需要支持的 shell 功能”;这意味着在 POSIX 的可选部分下可能允许某些标记的问题,例如 XSI 或用户可移植性。

Sotype被标记,因为它是一个可选功能。

checkbashisms除了从脚本中删除它们之外,我不知道有什么方法可以禁用 中的特定警告。


Ada*_*atz 7

考虑command -v foocommand -V foo代替type foo。有人告诉我它更可靠,更可能是内置的。

让我们在$PATH可执行文件、内置函数、函数和别名上进行测试:

#!/bin/sh

foo() {
   echo "in foo"
}
bar=foo

for cmd in sed command foo bar; do
  type "$cmd"
  command -V "$cmd"
  command -v "$cmd"
done
Run Code Online (Sandbox Code Playgroud)

输出(使用破折号0.5.11):

sed is /usr/bin/sed
sed is a tracked alias for /usr/bin/sed
/usr/bin/sed
command is a shell builtin
command is a shell builtin
command
foo is a shell function
foo is a shell function
foo
bar is an alias for foo
bar is an alias for foo
alias bar='foo'
Run Code Online (Sandbox Code Playgroud)

(注意:sed不是别名!也许这指的是 dash 的命令位置哈希表?)

尝试在 bash 中运行它,你会得到错误typecommand -V因为 bash 没有在非交互式脚本中启用别名。Bash 还会显示整个函数定义?——在多行——?given command -V,这真的很难解析。

POSIXcommand的选项定义为:

-p 使用 PATH 的默认值执行命令搜索,该值保证可以找到所有标准实用程序。

-v将一个字符串写入标准输出,指示 shell 将在当前 shell 执行环境(请参阅shell 执行环境)中使用的路径名或命令,以调用 command_name,但不调用 command_name。

  • 实用程序、常规内置实用程序、包含字符的 command_names 以及使用 PATH 变量找到的任何实现定义的函数(如命令搜索和执行中所述)应写为绝对路径名。
  • Shell 函数、特殊内置实用程序、与 PATH 搜索无关的常规内置实用程序和 Shell 保留字应仅写入其名称。
  • 别名应编写为代表其别名定义的命令行。
  • 否则,不应写入任何输出,退出状态应反映未找到名称。

-V向标准输出写入一个字符串,指示在当前 shell 执行环境中 shell 如何解释 command_name 操作数中给出的名称(请参阅shell 执行环境),但不要调用 command_name。尽管此字符串的格式未指定,但它应指明 command_name 属于以下哪个类别,并应包括所述信息:

  • 实用程序、常规内置实用程序以及使用 PATH 变量(如命令搜索和执行中所述)找到的任何实现定义的函数,都应进行标识,并在字符串中包含绝对路径名。
  • 其他外壳函数应标识为函数。
  • 别名应标识为别名及其定义包含在字符串中。
  • 特殊内置实用程序应标识为特殊内置实用程序。
  • 与 PATH 搜索无关的常规内置实用程序应标识为常规内置实用程序。(不需要使用“常规”一词。)
  • 外壳保留字应标识为保留字。

在编写 shell 脚本时,我强烈建议使用command -v而不是typeorcommand -V因为它是三个中唯一具有定义输出的一个。再说一次,我的大多数脚本通过一个静默的辅助函数调用它,该函数在确定我们是否有命令时完全忽略其输出:

we_have() { command -v "$1" >/dev/null 2>&1; }

if we_have obscure-command; then
  osbcure-command …
fi
Run Code Online (Sandbox Code Playgroud)

  • 我没有意识到 `command -v` 也支持函数,我只是将它用于命令。显然是的。 (2认同)