Search code examples
bashfish

Nested code blocks and subshells in fish script


I am working on converting one bash script to fish. I did most of it already, however there is a complex piece which has several nested and chained blocks.

Consider the following simplified piece in bash. Don't read too much into logic or commands, just follow the structure and pay attention to two subshells in () redirected to comm.

dummy () {
    {
    comm -13 \
        <(cat $CACHEDLIST | gawk  '{print $1}' FS='\t' OFS='\t') \
        <(cat $PDFLIST | gawk '{print $1}' FS='\t' OFS='\t') \
    } | fzf
}

I converted all {} blocks to begin; end. Then there are two subshell blocks redirected to comm -13 which I also converted to begin; end fish blocks and the overall block is piped to fzf. So the end result is quite straightforward:

function dummy
    begin
        comm -13 \
             <begin; echo "Arg1"; end \
             <begin; echo "Arg2"; end \
    end | fzf
end

If I run this tiny piece in shell I get:

(line 7): 'end' outside of a block

How come? My only guess is that line continuation is not respected, because the issue is definitely with two <begin; ...; end \ lines.


Solution

  • One way to translate this is to use an explicit named pipe in place of bash's process substitution construct. Note that the braces around comm aren't necessary, as there is only one command in the command group. That translates to one less begin-end pair in the fish function.

    function dummy
        begin
            mkfifo p1 p2
            gawk '{print $1}' FS='\t' OFS='\t' "$CACHEDLIST" > p1 &
            gawk '{print $1}' FS='\t' OFS='\t' "$PDFLIST" > p2 &
            comm -13 p1 p2 | fzf
            rm p1 p2
        end
    

    (You may want to make this more robust by creating p1 and p2 in a temp directory and making sure they get removed in the event of any error.)