如果我使用'echo',为什么会这样呢?

时间:2016-06-15 02:45:28

标签: bash if-statement

所以我现在只是试图遍历我当前的目录,在那里我调用以下bash脚本,每次找到一个打印出来的'我们找到了一个.c文件'。我有一个if语句来检查args因为我将扩展脚本,如果没有找到args它将会运行,并且一个arg将告诉脚本要查看的目录。

问题是,此代码不起作用:

if [ -z "$#" ]
    then
        for i in *.c; do
            echo "We found a .c file"
       done
fi

但是如果我添加echo "Test",它会起作用吗?

if [ -z "$#" ]
    echo "Test"
    then
        for i in *.c; do
            echo "We found a .c file"
       done
fi

我是bash的新手,并不知道为什么会发生这种情况。任何人都可以帮助我吗?

2 个答案:

答案 0 :(得分:7)

报告参数计数

$#绝不是空字符串 - 如果您未指定参数,$#会评估到0,它仍然是非空字符串字符串的-z测试)。

因此, [ -z "$#" ] 总是(逻辑上)为假。

您正在寻找的 - 使用惯用的Bash - 是:

if [[ $# -eq 0 ]]; then ...  # -eq compares *numerically*

正如anishsane在评论中指出的那样,符合POSIX的[ $# -eq 0 ]也适用于此;一般来说,除非你的明确意图是编写符合POSIX标准的shell代码 - 你最好坚持使用more predictable, more feature-rich (and marginally faster) Bash-specific constructs

或使用arithmetic evaluation

if (( $# == 0 )); then ...

至于为什么您的第二个代码段导致if分支被输入

您的放错地方 echo "Test" - 由于then关键字之前被放置,导致echo命令被解释< em>作为条件的一部分。

换句话说:评估的条件是有效的 [ -z "$#" ]; echo "Test",(两个)命令的列表,只有 last 命令的退出代码确定了条件的结果。

由于echo始终成功(退出代码0 [1] ,条件作为整体评估为(逻辑)真,并且输入了if分支。

[1] gniourf_gniourf在评论中指出您可以使简单的echo命令失败(使用退出代码1),如果您使用输入/输出重定向与无效的源/目标;例如,echo 'fail' > /dev/full (请注意,如果重定向源/目标从根本上无效 - 不存在的输入文件或无法创建/打开的输出文件(与可以打开的输出目标相反)具有写入权限但最终不能写入,例如Linux上的/dev/full - Bash甚至从未调用手头的命令,因为它在遇到无效时“放弃”重定向:
{ echo here >&2; echo hi; } >/dev/full # Linux: 'here' still prints (to stderr)
{ echo here >&2; echo hi; } >'' # invalid target: commands are never invoked)功能

答案 1 :(得分:3)

问题

以下循环永远不会运行:

if [ -z "$#" ]
    then
        for i in *.c; do
            echo "We found a .c file"
       done
fi

原因是$#是一个数字,0,1或更多。它永远不会是一个空字符串。因此[ -z "$#" ]将始终失败

此循环将始终运行:

if [ -z "$#" ]
    echo "Test"
    then
        for i in *.c; do
            echo "We found a .c file"
       done
fi

虽然[ -z "$#" ]始终失败,但第二个语句echo "Test"通常会返回成功退出代码。

解决方案

如果在命令行中未指定任何参数,则会将参数设置为当前目录中的所有.c个文件:

[ "$1" ] || set -- *.c
for i in "$@"; do
    echo "We found a .c file: $i"
done

因此,这允许您在命令行上指定文件名,并在脚本上运行这些文件名。如果您未指定任何内容,则会在所有.c个文件上运行。