pkgs.writeShellScriptBin error: syntax error, unexpected '@'

Hi all, I’ve written a short script derivation in my ~/.config/nixpkgs/config.nix that nix doesn’t like the bash syntax of.

{
  ...
  packageOverrides = pkgs: with pkgs; rec {
    ...
    foosh = pkgs.writeShellScriptBin “foolish” ‘’
      function help { ... }
      items=( “$@“ )
      (for e in "${items[@]}"; do [[ "$e" =~ ^(--)?help$ ]] && exit 0; done; exit 1) && help
      ...
    ‘’;
    ...
    myPackges = buildEnv {
      name = “my-packages”;
      paths = [
        foosh
        ...
      ];
   ...
}

I’m getting the following error, however:

% nix-env -iA nixpkgs.myPackages
error: syntax error, unexpected '@', at /Users/ldeck/.config/nixpkgs/config.nix:32:26

It appears nix config doesn’t like some permissible bash syntax.
What’s recommended for this situation?

There is some consideration to take when writing complex bash inside of Nix expressions. The antiquotation[1] syntax of Nix conflicts with bash’s expansions:

"${something}"

Between ${ and } is a Nix expression.

So the following:

"${somearray[@]}"

Between the antiquotation characters you have the Nix expression

somearray[@]

Which is not valid Nix (seen in Nix repl:)

nix-repl> somearray[@]
error: syntax error, unexpected '@', at (string):1:11

There is a way to escape antiquotations, from the Nix manual:

[In strings delimited with double-quotes (") the] special characters " and \ and the character sequence ${ must be escaped by prefixing them with a backslash ( \ ). Newlines, carriage returns and tabs can be written as \n , \r and \t , respectively.

Since ${ and '' have special meaning in indented strings, you need a way to quote them. $ can be escaped by prefixing it with '' (that is, two single quotes), i.e., ''$ . '' can be escaped by prefixing it with ' , i.e., ''' . $ removes any special meaning from the following $ . Linefeed, carriage-return and tab characters can be written as ''\n , ''\r , ''\t , and ''\ escapes any other character.

The second quote is for when you use indented strings (those that start with two single-quotes), which applies to your current case.


1: What the heck is antiquotation? It’s basically what Nix calls what other languages often all expansion or interpolation.

1 Like

Thanks @samueldr! That’s very helpful.

So to confirm, there is no such thing atm as a string literal (multi-line or not) that’s no interpolated, right?

There are two string literals, and they both support antiquotation. So: yes.