所以我现在只是试图遍历我当前的目录,在那里我调用以下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的新手,并不知道为什么会发生这种情况。任何人都可以帮助我吗?
答案 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。
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
个文件上运行。