Shell Scripts: Difference between revisions

From NixOS Wiki
imported>Milahu
(+ External builder.sh script)
imported>Milahu
(+ runCommand + builder.sh, fix links)
Line 25: Line 25:
   outputTxtPath = stdenv.mkDerivation rec {
   outputTxtPath = stdenv.mkDerivation rec {
     name = "output.txt";
     name = "output.txt";
     # disable unpackPhase etc https://github.com/NixOS/nixpkgs/issues/23099
     # disable unpackPhase etc
     phases = "buildPhase";
     phases = "buildPhase";
     builder = ./builder.sh;
     builder = ./builder.sh;
Line 43: Line 43:
</syntaxHighlight>
</syntaxHighlight>


see also [https://nixos.org/guides/nix-pills/working-derivation.html Nix Pills: Chapter 7. Working Derivation]
See also
 
* [https://github.com/NixOS/nixpkgs/issues/23099 make a derivation with no source]
* [https://nixos.org/guides/nix-pills/working-derivation.html Nix Pills: Chapter 7. Working Derivation]
 
=== runCommand + builder.sh ===
 
Instead of <code>stdenv.mkDerivation</code>, we can also use <code>runCommand</code> to call an external bash script:
 
<syntaxHighlight lang="nix">
# default.nix
{
  outputTxtPath = runCommand "output.txt" {
    nativeBuildInputs = [ coreutils jq ];
    # only strings can be passed to builder
    someString = "hello";
    someNumber = builtins.toString 42;
    someJson = builtins.toJSON { dst = "world"; };
  } (builtins.readFile ./builder.sh);
}
</syntaxHighlight>


== Packaging ==
== Packaging ==

Revision as of 13:22, 9 October 2021

the package writeShellScript can be used to add shell scripts to nix expressions

  someBuildHelper = { name, sha256 }:
    stdenv.mkDerivation {
      inherit name;
      outputHashMode = "recursive";
      outputHashAlgo = "sha256";
      outputHash = sha256;
      builder = writeShellScript "builder.sh" ''
        echo "hi, my name is ''${0}" # escape bash variable
        echo "hi, my hash is ${sha256}" # use nix variable
        echo "hello world" >output.txt
      '';
    };

External builder.sh script

Longer bash scripts are usually stored as external script files, and called from Nix:

# default.nix
{
  outputTxtPath = stdenv.mkDerivation rec {
    name = "output.txt";
    # disable unpackPhase etc
    phases = "buildPhase";
    builder = ./builder.sh;
    nativeBuildInputs = [ coreutils jq ];
    PATH = lib.makeBinPath nativeBuildInputs;
    # only strings can be passed to builder
    someString = "hello";
    someNumber = builtins.toString 42;
    someJson = builtins.toJSON { dst = "world"; };
  };
}
# builder.sh
echo "$someString $(echo "$someJson" | jq -r '.dst') $someNumber" >$out

See also

runCommand + builder.sh

Instead of stdenv.mkDerivation, we can also use runCommand to call an external bash script:

# default.nix
{
  outputTxtPath = runCommand "output.txt" {
    nativeBuildInputs = [ coreutils jq ];
    # only strings can be passed to builder
    someString = "hello";
    someNumber = builtins.toString 42;
    someJson = builtins.toJSON { dst = "world"; };
  } (builtins.readFile ./builder.sh);
}

Packaging

example:

# nix-build -E 'with import <nixpkgs> { }; callPackage ./default.nix { }'

{ stdenv
, lib
, fetchFromGitHub
, bash
, subversion
, makeWrapper
}:
  stdenv.mkDerivation {
    pname = "github-downloader";
    version = "08049f6";
    src = fetchFromGitHub {
      # https://github.com/Decad/github-downloader
      owner = "Decad";
      repo = "github-downloader";
      rev = "08049f6183e559a9a97b1d144c070a36118cca97";
      sha256 = "073jkky5svrb7hmbx3ycgzpb37hdap7nd9i0id5b5yxlcnf7930r";
    };
    buildInputs = [ bash subversion ];
    nativeBuildInputs = [ makeWrapper ];
    installPhase = ''
      mkdir -p $out/bin
      cp github-downloader.sh $out/bin/github-downloader.sh
      wrapProgram $out/bin/github-downloader.sh \
        --prefix PATH : ${lib.makeBinPath [ bash subversion ]}
    '';
  };

wrapProgram will move the original script to .github-downloader.sh-wrapped

Command not found

for example, the script throws the error svn: command not found, because the dependency subversion is missing.

when a command is missing, you can use nix-locate to find the package name. for example, the stat command:

$ nix-locate bin/stat | grep 'bin/stat$'
coreutils.out                                         0 s /nix/store/vr96j3cxj75xsczl8pzrgsv1k57hcxyp-coreutils-8.31/bin/stat

Posix Shell

some environments (like OpenWRT, via busybox) offer only a "limited" shell (sh instead of bash).

on nixos, posix shells are provided by the packages dash and posh

See also