Search code examples
printfzshfishgnu-coreutils

Is there a way to have fish-shell use GNU coreutils printf function?


Ran into an issue when running the following command in a fish shell:

❯ printf '%q\n' 'André Previn & London Symphony Orchestra'
%q: invalid conversion specification

I hadn't realized at first that fish actually has their own custom printf function that behaves in largely the same way as the GNU coreutils printf function, but does not support the q directive like GNU coreutils printf does.

fish-shell docs:

https://fishshell.com/docs/current/cmds/printf.html#format-specifiers

fish-shell printf documentation

GNU coreutils printf docs:

https://www.gnu.org/software/coreutils/manual/html_node/printf-invocation.html#printf-invocation

GNU coreutils printf documentation

Is there a way to tell fish-shell that I want it to use the GNU coreutils printf function instead of their customized printf function?

[Edit 1]: I hadn't realized that MacOS has it's own BSD-derived builtins that it uses, not the GNU coreutils builtins. Still am able to use the q option in zsh, but not in fish when running the following commands:

# in zsh
❯ printf '%q\n' 'test'
test

# fish, run in a zsh shell
❯ builtin printf '%q\n' 'test'
%q: invalid conversion specification

❯ command printf '%q\n' 'test'
printf: illegal format character q

Solution

  • When you run unqualified printf in fish, bash or zsh, it will run the given shell's builtin version of printf.

    There is an executable called printf on your system, probably in /usr/bin/printf or similar.

    To run that one, you can use command printf in fish or e.g. env printf (which would also work in bash).

    However, since you are on macOS it is not a GNU coreutils version, but macOS' own BSD-derived one.

    And since %q is a GNU-extension, it won't have it, and so running it won't actually help you.

    You can run e.g. bash's builtin printf by running bash:

    bash -c 'printf "%q\n" "$@"' printf 'echo $(hahaha)'
    

    (that second "printf" tells bash to call that process "printf" - it uses it as the argv0, $0)

    Fish's printf does not have %q, and if it did it would perform escaping for fish, not bash/zsh/sh - the quoting rules are different. It does have string escape instead.