Question

I am switching from bash to fish, but am having trouble porting over a convenience function I use often. The point of this function is to run make from the root directory of my source tree regardless of which directory my shell is currently in.

In bash, this was simply:

function omake {(
  cd $SOURCE_ROOT;
  make $@;
)}

Since fish doesn't have subshells, the best I've been able to do is:

function omake
    pushd
    cd $SOURCE_ROOT
    make $argv
    popd
end

This works, but with the caveat that after interrupting the fish version with ^C, the shell is still in $SOURCE_ROOT, but interrupting the bash version puts me back in the original directory.

Is there a way to write a script that works identically to the bash one in fish?

Was it helpful?

Solution

This is as close as I can get to a subshell:

function omake
    echo "cd $SOURCE_ROOT; and make \$argv" | fish /dev/stdin $argv
end

Process substitution does not seem to be interruptable: Ctrl-C does not stop this sleep cmd

echo (cd /tmp; and sleep 15)

However, fish has a very nice way to find the pid of a backgrounded process:

function omake
    pushd dir1
    make $argv &
    popd
end

Then, to stop the make, instead of Ctrl-C, do kill %make

OTHER TIPS

if you're using GNU coreutils, you can use env to do this (as user2394284 suggested would be nice).

env -C foo pwd

this will run pwd in a subdirectory called foo nicely. this generally interacts nicely with fish, for example it can be backgrounded nicely

the docs say:

Change the working directory to dir before invoking command. This differs from the shell built-in cd in that it starts command as a subprocess rather than altering the shell’s own working directory; this allows it to be chained with other commands that run commands in a different context.

For make specifically, you can use its -C option:

function omake
    make -C $SOURCE_ROOT $argv
end

Many other programs take the -C option. On top of my head: ninja, git

Otherwise, if you're content with a subshell anyway, a standalone script gives you just that, with the benefit that you can write it in any language, from Python to C, and won't have to rewrite it when you want to change your shell.

This could be written in any language:

#!/usr/bin/env fish
cd $SOURCE_ROOT
and exec make $argv

However, what really bugs me is the blatant omission of the -C option in env! Env can set environment variables and run programs; clearly, it would be nice to be able to set the working directory too! Here is a rudimentary cdrun script to make up for that:

#!/usr/bin/env fish
cd $argv[1]
and exec env $argv[2..-1]

or

#!/bin/sh
set cd="$1"
shift
cd "$cd" &&
exec env "$@"

Armed with the cdrun command, your omake function would be as simple as:

function omake
    cdrun $SOURCE_ROOT make $argv
end

or

omake() {
    cdrun "$SOURCE_ROOT" make "$@"
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top