-1

Before switching to fish shell, I frequently used various commands in zsh with which some_command. An example might be:

$ file `which zsh`
/opt/local/bin/zsh: Mach-O 64-bit executable arm64
/bin/zsh:           Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64
- Mach-O 64-bit executable x86_64] [arm64e:Mach-O 64-bit executable arm64e
- Mach-O 64-bit executable arm64e]
/bin/zsh (for architecture x86_64): Mach-O 64-bit executable x86_64
/bin/zsh (for architecture arm64e): Mach-O 64-bit executable arm64e

When I try to do this with fish it fails:

$ which zsh
/opt/local/bin/zsh

$ file `which zsh`
`which: cannot open ``which' (No such file or directory)
zsh`:   cannot open `zsh`' (No such file or directory)

Any idea of why this doesn't work fish as opposed to other more bash-like shells?

1
  • 2
    In general, even in Bash, Zsh, POSIX sh, etc., the use of backticks is strongly discouraged. See the POSIX standard, "Because of these inconsistent behaviors, the backquoted variety of command substitution is not recommended for new applications that nest command substitutions or attempt to embed complex scripts." Reference this U&L question. May 31 at 18:51

2 Answers 2

6

fish does not use backticks for command substitutions. Instead one can use parens: file (which zsh) or (in release 3.4.0 and later) file $(which zsh). These mean the same thing.

Check out fish for bash users for other differences.

2
  • Too bad it's not a little more terse/abbreviated regardless of the POSIX standard. <sigh> Wonder if there's a way to hack in an abbreviation of sorts?
    – ylluminate
    May 31 at 19:00
  • 1
    @ylluminate I'm not sure how you can get any more terse/abbreviated than (command). It's the same number of characters as using backticks, just (much) less error-prone when nesting. May 31 at 21:46
1

FWIW, in zsh, you'd rather use:

file -- =zsh

Or:

() {file -- $1:c} zsh

file $(which zsh) (the modern version of the deprecated file `which zsh`) would only work if there was no alias or function also defined for zsh and if the path to the zsh command didn't start with - nor end in newline characters¹ and didn't contain characters of $IFS (space, tab, newline and nul by default).

file -- "$(whence -p zsh)"

Would be more correct (which in zsh being an alias for whence -c, -c for csh, which being originally a csh script for csh users).

In fish, as fish's maintainer already said, command substitution is with (...) or also $(...) in recent versions (the latter can be used inside double quotes).

Contrary to zsh, fish doesn't have which builtin, so the behaviour will vary with the system you're on, which being a non-standard, often broken command.

fish has a type builtin command though which supports a -P option to force a $PATH lookup like zsh's whence -p.

By default command substitutions are split on newline characters. If using $(...) inside double quotes however, there's no splitting but all the trailing newline characters are removed.

So with fish, a more correct version would be:

file -- "$(type -P zsh)"

or with older versions:

file -- (type -P zsh | string collect)

(with one difference from the "$(...)" in that if type produces no output (or only newlines) it will not pass any argument to file instead of one empty argument).


¹ for which zsh to return something ending in newline, you'd need to have done hash zsh=$'/path/to/some/fileendinginnewline\n\n' for instance though, which is quite contrived here.

3
  • string collect --allow-empty was added in fish 3.4.0, same as $(). It will work in the exact same versions.
    – faho
    Jun 1 at 6:05
  • Also @ridiculous_fish is not fish's "original author", the original author has left the project. He is the maintainer, tho.
    – faho
    Jun 1 at 6:06
  • Thanks @faho. Both should be fixed now. Jun 1 at 6:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.