Use Exit Status of A Command in A Fish Shell Function
Tags: fishshell, fish, scripting, exitstatus
Published: 2020-03-16 13:37:51

---
title: Use Exit Status of A Command in A Fish Shell Function
tags: fishshell,fish,scripting,exitstatus
canonical_url: https://www.oncrashreboot.com/use-exit-status-of-command-in-fish-function
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/8hywpkzi0o34jzoq3idm.jpg
published: true
---

[Fish shell](https://fishshell.com/) is a user-friendly and a feature-rich alternative to the Bash shell. Think [Zsh](https://www.zsh.org/), 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](https://github.com/BurntSushi/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[](#status-variable "Permanent link")

Fish Shell stores the exit status of the last command in the `$status` variable.

```shell
➤ 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.

```shell
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](https://fishshell.com/docs/current/index.html#variables-status).

## Use `and`, `or` Combiners[](#use-and-or-combiners "Permanent link")

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.

```shell
➤ 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.

```shell
➤ rg "blahblah" > /dev/null
   and echo found
   or echo not found
```

You can read more about `and`, `or` combiners in [fish shell documentation](https://fishshell.com/docs/current/tutorial.html#tut_combiners).

### Use `and`, `or` Combiners with `begin`[](#use-and-or-combiners-with-begin "Permanent link")

We can do complex operations like running more than one command using `begin` with the combiners.

```shell
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](https://fishshell.com/docs/current/commands.html#begin).

## Use `if`[](#use-if "Permanent link")

You do not have to use the `$status` variable and `test` command. You can use `if` directly.

```shell
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[](#store-output-of-a-command-in-a-variable-and-test-it "Permanent link")

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,

```shell
➤ 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

```shell
+ 12dc1f697b714336b118f1361fa49a4ef71c44b7commits found
```

Then I run it in a repository whose `HEAD` is in sync with the upstream. The output is,

```shell
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[](#test-output-as-string "Permanent link")

Consider the following script,

```shell
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](https://fishshell.com/docs/current/commands.html#test).

### Count Number Of Lines In Output[](#count-number-of-lines-in-output "Permanent link")

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.

```shell
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](https://fishshell.com/docs/current/commands.html#count).

## Example[](#example "Permanent link")

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](https://github.com/talha131/dotfiles/blob/master/fish/functions/tm_git_push.fish)

---
Cover image attribution: [David Clode](https://unsplash.com/@davidclode?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge)