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"]
docker run [my_image]でechoが実行されない理由
以下は完全な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
ループが次に追加されました。各繰り返します。これは必要ありません。ディレクトリ名からIDを取得するのは、適切なループで行うのが最善です。このループは、後で配列を使用してIDを保存すると消えます。
中間ファイルの検索に使用する代わりに、単純な
find
ファイル名のグロービングパターンを使用します。私たちは彼らがそこにいることを知り、彼らの名前も知っています。処理されたばかりの中間ファイルはループ内で削除されます。
連続を使用してコードを読みやすくします。
通話が
wait
削除されました。待つバックグラウンドタスクはありません。
all_ids
次のバリアントは、一時ファイルの代わりに配列にIDを保存します。
#!/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