我尝试使用 Entrypoint.sh 运行 docker,但它不执行 .sh 行:
echo `ls -d /input/sub-*/ | sed -e 's/.*sub-\(.*\)\//\1/' | split -l 8 - participants_`
我把它写在dockerfile中:
ENTRYPOINT ["bash", "-c", "source /code/entrypoint.sh | ts '[%Y-%m-%d %H:%M:%S]' &>> /output/stderr.log"]
为什么 echo 不在 docker run [my_image] 内执行
这是完整的entrypoint.sh代码:
#! /bin/bash
alias time='/usr/bin/time -f "%C --- CPU:\t%E real,\t%U user,\t%S
sys\t%P\tMem:\t%KkiB avg.,\t%MkiB max.\tExit:\t%x"'
echo `ls -d /input/sub-*/ | sed -e 's/.*sub-\(.*\)\//\1/' | split -l 8 -
participants_`
while read input_bids_path
do
participants_id=$(basename $input_bids_path)
LD_LIBRARY_PATH=/usr/lib/fsl/5.0:$LD_LIBRARY_PATH
time 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 $(cat $participants_id) -w
/output
# rm -r /input/$participants_id
done < <(find /input -name "*participants_*" -type f)
echo `rm -r /input/$participants_id`
wait `jobs -p` && echo __ok__ || echo __err__
答案1
该脚本中有许多内容是错误的或可以改进的。
该问题的主要问题似乎是为什么两次调用echo
不产生任何输出。
当您使用命令替换时,例如
echo `rm file`
或同等的
echo $(rm file)
那么echo
将会得到输出反引号内或$(...)
.您的命令替换都不会产生任何输出。您在反引号中使用的两个命令都会修改文件,但同样不会将输出生成到其标准输出流(通常会在终端中显示的内容)。这意味着echo
除了每个空行之外,两个调用都不会产生任何输出。
一般来说,echo $(...)
它是一种反模式,意味着你可以用更好的方式做同样的事情。
如果你做想要输出某个管道的结果pipeline
,而不是编写
echo $(pipeline)
你会简单地说
pipeline
将显示的输出pipeline
,因为命令的输出通常显示在终端中。
在下面的代码中,我插入了一些printf
语句,这些语句将在脚本中输出相关的“进度信息”。
这是脚本的修改版本,完全未经测试(因为我无权访问您使用的工具或输入文件),但它应该模仿您的脚本正在执行的操作,包括创建这些中间文件(不需要这些文件,稍后我将展示如何删除它们)。
#!/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
修复:
该
time
命令不需要仅仅因为其-f
选项有一个长选项参数而成为别名。无论如何,别名不会在脚本中扩展。我只是将参数保存在字符串中,并在调用时使用它time
。您的循环已添加到
LD_LIBRARY_PATH
in每个迭代。这是不需要的。从目录名称获取 ID 最好在适当的循环中完成。当我们使用数组来存储 ID 时,这个循环稍后就会消失。
我们不使用它们
find
来定位中间文件,而是将它们与简单的文件名通配模式一起使用。我们知道他们就在那里,也知道他们叫什么名字。刚刚处理的中间文件在循环内被删除。
通过使用续行使代码变得可读。
的呼叫
wait
已被删除。没有需要等待的后台任务。
以下变体将 ID 存储在数组中,all_ids
而不是临时文件中:
#!/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