Quantcast
Viewing all articles
Browse latest Browse all 2

Answer by Kusalananda for shell script inside docker

There's a number of things in this script that are wrong or that can be improved.

The main issue in the question seems to be why the two calls to echo does not produce any output.

When you use a command substitution, like in

echo `rm file`

or the equivalent

echo $(rm file)

then the echo will get the output of the command within the backticks or inside the $(...). Neither of your command substitutions produces any output. Both commands that you use within backticks modify files, but again, neither produces output to their standard output stream (what would ordinarily be displayed in the terminal). This means that both calls to echo will produce no output either, apart from an empty line each.

In general, echo $(...) is an anti-pattern, meaning you can do the same thing in a much better way.

If you do want to output the result of some pipeline pipeline, then instead of writing

echo $(pipeline)

you would simply say

pipeline

The output of pipeline would be displayed, as the output of commands are usually displayed in the terminal.

In the code below, I have inserted a couple of printf statements that will output the relevant "progress information" in the script(s).


Here's a modified version of the script which is totally untested (as I don't have access to the tools that you use, or the input files), but it should mimic what your script is doing, including creating those intermediate files (these are not needed, and I'll show how to get rid of them later).

#!/bin/bash

export LD_LIBRARY_PATH="/usr/lib/fsl/5.0:$LD_LIBRARY_PATH"

timefmt="%C --- CPU:\t%E real,\t%U user,\t%S sys\t%P\tMem:\t%KkiB avg.,\t%MkiB max.\tExit:\t%x"

for dirpath in /input/sub-*/; do
    name=$(basename "$dirpath")
    id=${name#sub-}
    printf '%s\n' "$id"
    printf 'Found ID: %s\n' "$id" >&2
done | split -l 8 - participants_

for participants_id in participants_*; do
    ids=( $(<"$participants_id") )

    printf 'Processing ID: %s\n' "${ids[@]}" >&2

    /usr/bin/time -f "$timefmt" \
    fmriprep /input /output participant \
        --fs-license-file /opt/freesurfer/license.txt \
        --fs-no-reconall --use-aroma \
        --ignore fieldmaps --n_cpus 12 --force-bbr \
        --participant_label "${ids[@]}" \
        -w /output

    rm -f "$participants_id"
done

Fixes:

  1. The time command does not need to be an alias just due to having a long option argument to its -f option. Aliases aren't expanded in scripts anyway. I simply save the argument in a string and use that when invoking time.

  2. Your loop added to LD_LIBRARY_PATH in each iteration. This was not needed.

  3. The getting of the IDs from the directory names is better done in a proper loop. This loop will disappear later when we use an array to store the IDs instead.

  4. Rather than using find to locate the intermediate files, we just use them with a simple filename globbing pattern. We know they're right there and what their names are anyway.

  5. The intermediate file just processed is deleted inside the loop.

  6. The code is made readable through use of line continuations.

  7. The call to wait was removed. There are no background tasks to wait for.

The following variation stores the IDs in an array, all_ids instead of in temporary files:

#!/bin/bash

export LD_LIBRARY_PATH="/usr/lib/fsl/5.0:$LD_LIBRARY_PATH"

timefmt="%C --- CPU:\t%E real,\t%U user,\t%S sys\t%P\tMem:\t%KkiB avg.,\t%MkiB max.\tExit:\t%x"

all_ids=( /input/sub-*/ )
all_ids=( "${all_ids[@]#/input/sub-}" ) # remove "/input/sub-" from each item
all_ids=( "${all_ids[@]%/}" )           # remove the trailing "/" from each item

printf 'Found ID: %s\n' "${all_ids[@]}" >&2

n=0
ids=( "${all_ids[@]:0:8}" ) # pick out the first eight IDs

# Loop until the first ID in the ids array is empty
while [ -n "${ids[0]}" ] ; do
    printf 'Processing ID: %s\n' "${ids[@]}" >&2

    /usr/bin/time -f "$timefmt" \
    fmriprep /input /output participant \
        --fs-license-file /opt/freesurfer/license.txt \
        --fs-no-reconall --use-aroma \
        --ignore fieldmaps --n_cpus 12 --force-bbr \
        --participant_label "${ids[@]}" \
        -w /output

    n=$(( n + 1 ))
    ids=( "${all_ids[@]:n*8:8}" ) # pick out the next eight IDs
done

Viewing all articles
Browse latest Browse all 2

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>