DEV Community

Cover image for Use Exit Status of A Command in A Fish Shell Function
Talha Mansoor
Talha Mansoor

Posted on • Originally published at oncrashreboot.com on

Use Exit Status of A Command in A Fish Shell Function

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.

trueecho $status 0 ➤ falseecho $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.

  1. and runs the command if the last command execution was successful.
  2. 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

Top comments (0)