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:
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 invokingtime
.Your loop added to
LD_LIBRARY_PATH
in each iteration. This was not needed.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.
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.The intermediate file just processed is deleted inside the loop.
The code is made readable through use of line continuations.
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