Fish shell:检查函数是否提供了参数

36

我正在创建一个函数(如下),它可以接受一个参数:目录。我使用 -d 选项测试 $argv 是否为目录,但似乎不起作用,即使没有提供任何参数也会始终返回 true。我还尝试使用 test -n $argv -a -d $argv 来测试 $argv 是否为空字符串,但这会返回 test: Missing argument at index 1 错误。我应该如何测试函数是否提供了任何参数?从我的理解上来看,为什么 test -d $argv 不起作用,因为空字符串不是目录,所以应该为 false。

function fcd
     if test -d $argv
         open $argv
     else
         open $PWD
     end
 end

感谢您的帮助。

5个回答

48

count 是正确的方式来实现这个。对于检查是否存在任何参数的常见情况,您可以使用它的退出状态:

function fcd
    if count $argv > /dev/null
        open $argv
    else
        open $PWD
    end
end

为了回答你的第二个问题,如果$argv为空,则test -d $argv返回true,因为POSIX规定当test只传递一个参数时,它必须"如果$1不为空,则退出true(0);否则,退出false"。因此,当$argv为空时,test -d $argv意味着test -d,因为-d不为空,所以它必须返回true!哎呀!编辑添加了一个缺失的end,感谢Ismail的注意。

2
以上代码缺少一个 end,由于字符数少于最小的6个字符,我无法编辑 - 请更新上面的答案... - Ismail Moghul
3
我曾因 > /dev/null 而感到困惑,所以我找到了一种更详细的替代方法,但对我来说更易读:if test (count $a) -gt 0; ...; end - FMCorz

33
在 Fish 2.1+ 中,你可以为参数命名,这使得代码更有语义。
function fcd --argument-names 'filename'
    if test -n "$filename"
        open $filename
    else
        open $PWD
    end
end

2
“-a”是文档中提到的简写标志:https://fishshell.com/docs/current/commands.html#function - Sgnl
2
在调用test时,$filename周围的引号很重要。否则,如果未提供参数,则会出现“test:缺少索引2处的参数”的错误提示。 - Raman

14
if not set -q argv[1]
    echo 'none'
else
    echo 'yes'
end

来自man set页面:

   set ( -q | --query ) [SCOPE_OPTIONS] VARIABLE_NAMES...

-q--query 测试指定的变量名是否已定义。不输出任何内容,但内置退出状态是未定义的变量数。


3
太好了,我在if语句中使用了set -q $argv[1],结果是错误的。我们不需要展开argv。谢谢! - LeOn - Han Li

6

$argv 是一个列表,所以如果该列表中有元素,您需要查看第一个元素:

if begin; test (count $argv) -gt 0; and test -d $argv[1]; end
    open $argv[1] 
else
    open $PWD
end

4
也许与主题无关,但我想为这个问题添加另一个视角。
我想扩大测试shell代码的范围,使用fisherman组开发的库进行测试。
使用mock可以检查open命令是否安全调用,没有副作用。
例如:
function fcd
    if count $argv > /dev/null
        open $argv
    else
        open $PWD
    end
end
mock open 0 "echo \$args"
fcd "cool" # echoes cool
mock open 0 "echo \$args"
fcd # echoes $PWD

这是一个最近出现的库,但它可以帮助测试可能存在危险的事物,例如 rm 命令。

mock rm 0 "echo nothing would happen on \$args"
rm "some file" # simply echoes the message with a list of the files that would been affected

我希望它能给出更多创新的观点。
附:抱歉做了明显的宣传,但我认为这是一个很酷的想法,应该被shell脚本程序员采纳,测试和增加shell脚本的可持续性是疯狂的。 :P
编辑:我最近注意到我发布的示例存在错误,请不要使用rm *,因为星号不会被视为参数,而是fish shell将星号扩展为找到的文件列表,命令只模拟第一个调用,这意味着第一个文件将被模拟所忽略,但所有后续文件都会被删除,因此,请在尝试示例时小心,使用单个文件作为示例,而不是通配符。

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