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

  • Typically when you install GNU coreutils, you get the utilities with a 'g' in front of them. For example: 'gls', 'ggrep', 'gawk', 'gsed', etc.

    So, for MacOS after running brew install coreutils, you'll find gprintf probably lives in /opt/homebrew/bin/gprintf. Run this command to see where yours lives:

    > type gprintf
    /path/to/gnu/coreutils/gprintf
    

    The answer to what you're asking would be to wrap gprintf in a printf function:

    # BUT DON'T ACTUALLY DO THIS
    > function printf
        gprintf $argv
    end
    
    > printf '%q\n' 'André Previn & London Symphony Orchestra'
    'André Previn & London Symphony Orchestra'
    

    Now, that being said, I would not recommend this. You likely have other scripts in your environment that expect printf to behave like Fish's printf does. Don't shadow it. If you want/need coreutils printf behavior, just use the 'g' varaiant. If you don't have a proper 'g' variant, then make that instead:

    # Do this if you have gprintf
    > gprintf '%q\n' 'André Previn & London Symphony Orchestra'
    'André Previn & London Symphony Orchestra'
    
    # Do this if you don't have gprintf
    function gprintf
        # If you have a printf util:
        # /path/to/gnu/coreutils/printf $argv
    
        # Or, farm to bash
        # bash -c 'printf "%q\n" "$@"' $argv
    end