도커 내부의 쉘 스크립트

도커 내부의 쉘 스크립트

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

수리하다:

  1. 해당 옵션에 긴 옵션 인수가 있다고 해서 명령 time이 별칭일 필요는 없습니다 . -f그럼에도 불구하고 별칭은 스크립트에서 확장되지 않습니다. 저는 매개변수를 문자열로 저장하고 호출할 때 사용합니다 time.

  2. LD_LIBRARY_PATH루프가 다음에 추가되었습니다 .반복합니다. 이것은 필요하지 않습니다.

  3. 디렉터리 이름에서 ID를 가져오는 것은 적절한 루프에서 수행하는 것이 가장 좋습니다. 이 루프는 나중에 배열을 사용하여 ID를 저장할 때 사라집니다.

  4. 중간 파일을 찾는 데 사용하는 대신 find간단한 파일 이름 글로빙 패턴을 사용합니다. 우리는 그들이 거기 있다는 것을 알고 그들의 이름도 알고 있습니다.

  5. 방금 처리된 중간 파일은 루프 내에서 삭제됩니다.

  6. 연속을 사용하여 코드를 읽기 쉽게 만듭니다.

  7. 통화가 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

관련 정보