user14492
user14492

Reputation: 2234

Fish shell: Check if argument is provided for function

I am creating a function (below) with which you can provide an argument, a directory. I test if the $argv is a directory with -d option, but that doesn’t seem to work, it always return true even if no arguments are supplied. I also tried test -n $argv -a -d $argv to test is $argv is empty sting, but that returns test: Missing argument at index 1 error. How should I test if any argument is provided with the function or not? Why is test -d $argv not working, from my understanding it should be false when no argument is provided, because empty string is not a directory.

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

Thanks for the help.

Upvotes: 37

Views: 21463

Answers (5)

Duke
Duke

Reputation: 7444

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

From the man set page:

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

-q or --query test if the specified variable names are defined. Does not output anything, but the builtins exit status is the number of variables specified that were not defined.

Upvotes: 15

markcial
markcial

Reputation: 9323

Maybe is non related, but i would like to add another perspective for the question.

I want to broaden the insight to a wider scope the scope of testing the shell code with the libraries developed in the fisherman group.

With mock you can check if the open command is called safely without side effects.

Example.:

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

Is a recent library, but it could help to test things that might be dangerous, like for example 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

I hope that it gives a more out of the box point of view

P.S.: Sorry for the blatant publicity, but i think that is a cool idea that would be nice to be adopted by shell scripters, to test and add sustainability to shell scripts is nuts. :P

EDIT: i recently noticed a bug about the sample i posted. Please do not use rm *, because the asterisk is not treated as a param, instead fish shell expands asterisk to the list of files found and the command only mocks the first call, this means that the first file would be ignored by the mock, but all the subsequent files will get erased so please be careful if trying the sample and use a single file for the example not the wildcard.

Upvotes: 4

steevee
steevee

Reputation: 2558

In fish 2.1+ at least, you can name your arguments, which then allows for arguably more semantic code:

function fcd --argument-names 'filename'
    if test -n "$filename"
        open $filename
    else
        open $PWD
    end
end

Upvotes: 34

ridiculous_fish
ridiculous_fish

Reputation: 18551

count is the right way to do this. For the common case of checking whether there are any arguments, you can use its exit status:

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

To answer your second question, test -d $argv returns true if $argv is empty, because POSIX requires that when test is passed one argument, it must "Exit true (0) if $1 is not null; otherwise, exit false". So when $argv is empty, test -d $argv means test -d which must exit true because -d is not empty! Argh!

edit Added a missing end, thanks to Ismail for noticing

Upvotes: 49

glenn jackman
glenn jackman

Reputation: 246774

$argv is a list, so you want to look at the first element, if there are elements in that list:

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

Upvotes: 6

Related Questions