在shell脚本中,${-#*i}是什么意思?

19

在CentOS 6的文件/etc/profile中有一个for循环:

for i in /etc/profile.d/*.sh ; do
    if [ -r "$i" ]; then
        if [ "${-#*i}" != "$-" ]; then
            . "$i"
        else
            . "$i" >/dev/null 2>&1
        fi
    fi
done

上述for循环中的${-#*i}是什么意思?
感谢任何帮助。

5
当我看到标题时,我以为你在那里审查了一个非常糟糕的词... - Marco13
3个回答

12

$- 是Shell标志。

${-#*i} 表示Shell标志减去第一个匹配的 *i

如果这两者不相等,则Shell被视为交互式(存在标志i)。


对我来说最让人困惑的是循环也使用 i 作为一个变量 - 但在 ${-#*i} 中它只是字符 i - pmoubed

11

请看cuonglmUnix & Linux上关于“${-#*i}” != “$-”是什么意思?最佳回答

$-是shell本身在启动时或使用内置命令set设置的当前选项标志:

$ echo $-
himBH
$ set -a
$ echo $-
ahimBH

"${-#*i}" 是用于字符串移除的语法:(来自POSIX文档

${parameter#[word]}

删除最小前缀模式。单词将被扩展以生成一个模式。参数扩展将导致参数,其中由模式匹配的最小前缀部分被删除。

如果存在,则单词不应以未引用的 '#' 开头。

${parameter##[word]}

删除最大前缀模式。单词将被扩展以生成一个模式。参数扩展将导致参数,其中由模式匹配的最大前缀部分被删除。

所以${-#*i} 移除到第一个 i 字符的最短字符串:

enter code here
$ echo "${-#*i}"
mBH
在您的情况下,if [ "${-#*i}" != "$-" ] 检查您的Shell是否为交互式。

3
我已经编辑了您的答案,以正确引用和归属原作者。请参阅帮助中心的引用部分;推荐引用“仅涉及相关部分”,而不是完整回答。 - Benjamin W.

7

tl;dr:

如果当前shell是交互式的,则条件[ "${-#*i}" != "$-" ]评估为逻辑true,此时退出码设置为0,表示true,这会导致执行包含if语句的then分支。

该条件和问题中的代码整体上故意只使用符合POSIX标准的shell语言语法和命令,以便实现可移植性(适用于所有可能充当/bin/sh的POSIX兼容shell)。

请注意,如果可以假定bash是shell,例如,相同的条件可以更易读地表示为
[[ $- == *i* ]]


解释

  • ${-#*i} 是一个参数扩展,它从命名参数$-的值中移除最短的匹配模式 *i 的前缀(#)。(命名参数更常被称为变量)。

  • $- 是一个特殊参数,它(链接和强调已添加):

    根据在调用时、通过设置特殊内置命令或隐式地由 shell 指定,将扩展为当前选项标志(单字母选项名称连接成的字符串)。

  • 交互式 shell会隐式地$-的值添加选项标志i;换句话说:在$-的值中出现字母i意味着手头的 shell 是交互式的,反之,缺少i则意味着该 shell 是非交互式的。

  • 因此,在参数扩展${-#*i}中,只有当存在i时,模式*i才会匹配到$-的值中,并且通过移除*i匹配的内容,返回$-的一个子字符串(在这种情况下是后缀)。
    换句话说:只有在交互式shell中,${-#*i}不等于$-,因为在非交互式shell中,由于缺少i,参数扩展没有效果,两个操作数相等。


这个问题中的代码作用 总体而言:

简而言之:该代码使用在/etc/profile.d路径下找到的shell脚本来初始化当前shell;更具体地说:

  • 位于目录/etc/profile.d下,文件名为*.sh且当前用户有读取权限(-r)的脚本将按照字母顺序逐个传递给. (dot) utility执行。点实用程序(dot utility)会在当前 shell中执行每个文件中的命令,通常是为了定义别名、函数和环境变量。这通常被称为源化(sourcing)文件。

  • 每个已源化脚本产生的输出(output)在当前 shell 是否为交互式(interactive)下处理方式不同:

    • 交互式(interactive) shell:输出被直接传递(passed through)(可以在交互式 shell 中看到)。

    • 非交互式(noninteractive) shell:输出被抑制(suppressed)(使用 >/dev/null 2>&1 是 POSIX 兼容的方法来静音stdout和stderr)。


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