Use Exit Status of A Command in A Fish Shell Function
Talha Mansoor
Posted on March 16, 2020
Fish shell is a user-friendly and a feature-rich alternative to the Bash shell. Think Zsh, but with saner and user-friendly defaults. Fish shell "just works", requiring minimal customizations. You do not have to waste time scouring the internet for tutorials and example config files.
When writing scripts, a lot of time you run into cases where you have to get the exit status of the last command executed. In this article, I detail all the ways you can use to the exit status of a command.
In the following examples, I am going to use rg
, i.e. ripgrep. It’s a modern and faster equivalent of the traditional grep
and ack
commands. rg
also has a sane default configuration that does not require you to enable command switches to do mundane tasks like searching recursively or respecting .gitignore
rules.
$status
variable
Fish Shell stores the exit status of the last command in the $status
variable.
➤ true
➤ echo $status
0
➤ false
➤ echo $status
1
➤ blahblah
fish: Unknown command blahblah
➤ echo $status
127
Use it with if
and test
in your scripts.
function example -d 'Example Fish function'
rg $argv[1] > /dev/null
if test $status -eq 0
echo "$argv[1] found"
else
echo "$argv[1] not found"
end
end
Notice how I used test
to check the value of $status
variable.
You can read more about $status
variable in fish documentation.
Use and
, or
Combiners
Fish also supports and
and or
.
-
and
runs the command if the last command execution was successful. -
or
runs the command if the previous command execution failed.
➤ rg "blahblah" > /dev/null; and echo "found"; or echo "not found"
We can use newlines instead of ;
. Use Alt (⌥Option key on macOS) and ⌤Enter key to insert newlines.
➤ rg "blahblah" > /dev/null
and echo found
or echo not found
You can read more about and
, or
combiners in fish shell documentation.
Use and
, or
Combiners with begin
We can do complex operations like running more than one command using begin
with the combiners.
function example -d 'Example Fish function'
rg $argv[1] > /dev/null
and begin
echo "$argv[1] found"
end
or begin
echo "$argv[1] not found"
end
end
Between begin
and end
you can write more commands or even more conditions.
You can read more about begin
here.
Use if
You do not have to use the $status
variable and test
command. You can use if
directly.
function example -d 'Example Fish function'
if rg $argv[1] > /dev/null
echo "$argv[1] found"
else
echo "$argv[1] not found"
end
end
Store output of a command in a variable and test
it
Sometimes reading the exit status of a command is not enough. Take git cherry
, for example. This command returns the unpushed git commits.
Whether it finds unpushed git commits push or not, it always exits successfully.
Consider the following script,
➤ git cherry
and echo commits found
or echo commits not found
I run it in a repository whose HEAD
is one commit ahead of the upstream. The output I get is
+ 12dc1f697b714336b118f1361fa49a4ef71c44b7commits found
Then I run it in a repository whose HEAD
is in sync with the upstream. The output is,
commits found
Even though git cherry
couldn’t find any unpushed git commits. I cannot employ previously suggested methods that rely on the exit status of the command.
In this case, we have to test
the output of the command.
Test Output As String
Consider the following script,
function example -d 'Example Fish function'
if test -n "(git cherry)"
echo commits found
else
echo commits not found
end
end
Do you notice the quotes around (git cherry)
? It is crucial.
See, git cherry
can return more than one line in the output. With quotes, the Fish shell treats the command output as one argument, even if it has newlines.
If we remove the quotes, then if newlines are present, the output becomes a list or an array.
test -n
returns true if the length of the string is non-zero.
You can read about test
command here.
Count Number Of Lines In Output
It is not necessary to use quotes. We can refactor the above script to handle arrays and then count the number of indices in the array.
function example -d 'Example Fish function'
if test (count (git cherry)) -ne 0
echo commits found
else
echo commits not found
end
end
count
command returns the number of elements in the list. So with count (git cherry)
, we read the number of lines returned and compare it to 0.
test -ne
returns true if the first number is not equal to the second number.
count
documentation is available here.
Example
You can see the above discussion in action in a script that I wrote to periodically push out git commits to the upstream, every 10 seconds.
Source Code of tm_git_push
script
Cover image attribution: David Clode
Posted on March 16, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.