Bash는 작업 대기 및 작업 수 제한

Bash는 작업 대기 및 작업 수 제한

중복 가능성:
4개의 작업을 동시에 실행하는 중입니다. 어떻게 해야 합니까?

루프가 명령을 호출한다고 가정합니다.

 grep -v '#' < files.m3u | sed 's/\\\\/\/\//g' | sed 's/\\/\//g' | while read line
 do
    filename=$(basename "$line")
    avconv -i "$line" "${filename%.*}.wav"
 done

avconv 뒤에 &를 배치하면 각 파일에 대해 avconv가 지속적으로 생성됩니다. 이제 저는 두 가지 일을 하고 싶습니다:

  • 생성되는 프로세스 수를 4개로 제한하고 싶습니다.
  • 루프가 완료된 후 마지막 루프가 준비될 때까지 기다리고 싶습니다.

답변1

각각의 새로운 하위 프로세스의 PID를 기억할 수 있습니다( $!시작 후 확인). 아직 존재하는 자식 수(예: 통과 kill -0)를 주기적으로 확인하고, 숫자가 떨어지면 새 자식을 생성하는 등의 작업을 수행합니다. 마지막으로, 그냥 wait.

같은 이유로 제가 작성한 스크립트는 다음과 같습니다.

#! /bin/bash

## Tries to run commands in parallel. Commands are read from STDIN one
## per line, or from a given file specified by -f.
## Author: E. Choroba

file='-'
proc_num=$(grep -c ^processor'\b' /proc/cpuinfo)
prefix=$HOSTNAME-$USER-$$
sleep=10

children=()
names=()

if [[ $1 =~ ^--?h(elp)?$ ]] ; then
    cat <<-HELP
    Usage: ${0##*/} [-f file] [-n max-processes] [-p tmp-prefix] -s [sleep]
      Defaults:
        STDIN for file
        $proc_num for max-processes (number of processors)
        $prefix for tmp-prefix
        $sleep for sleep interval
    HELP
    exit
fi

function debug () {
    if ((DEBUG)) ; then
        echo "$@" >&2
    fi
}

function child_count () {
    debug Entering child_count "${children[@]}"
    child_count=0
    new_children=()
    for child in "${children[@]}" ; do
        debug Trying $child
        if kill -0 $child 2>/dev/null ; then
            debug ... exists
            let child_count++
            new_children+=($child)
        fi
    done

    children=("${new_children[@]}")
    echo $child_count
    debug Leaving child_count "${children[@]}"
}

while getopts 'f:n:p:s:' arg ; do
    case $arg in
        f ) file=$OPTARG ;;
        n ) proc_num=$((OPTARG)) ;;
        p ) prefix=$OPTARG;;
        s ) sleep=$OPTARG;;
        * ) echo "Warning: unknown option $arg" >&2 ;;
    esac
done

i=0
while read -r line ; do
    debug Reading $line
    name=$prefix.$i
    let i++
    names+=($name)

    while ((`child_count`>=proc_num)) ; do
        sleep $sleep
        debug Sleeping
    done

    eval $line 2>$name.e >$name.o &
    children+=($!)
    debug Running "${children[@]}"
done < <(cat $file)

debug Loop ended
wait
cat "${names[@]/%/.o}"
cat "${names[@]/%/.e}" >&2
rm "${names[@]/%/.o}" "${names[@]/%/.e}"

답변2

~에서링크 문제, 귀하의 변경 사항에 맞춰 조정됩니다.

sed -n -e '/#/!s,\\,/,g' files.m3u | xargs -d '\n' -I {} -P 4 \
    sh -c 'line=$1; file=${line##*/}; avconv -i "$line" "${file%.*}.wav"' avconv_sh {}

마찬가지로 GNU xargs또는 일부 버전을 지원하는 -d것이 -P필요합니다. 또한 입력 파일의 줄 시작과 끝 부분에 추가 공백이 있는지 주의하세요. 공백이 있는 경우 이 코드 조각이 공백을 유지하므로 문제가 발생할 수 있습니다.

답변3

이것이 내가 해결한 방법입니다. 달러 주셔서 감사합니다! 팁

#!/bin/bash
children[0]=0
children[1]=0
children[2]=0
children[3]=0

i=0
grep -v '#' < files.m3u | sed 's/\\\\/\/\//g' | sed 's/\\/\//g' | while read line
do
    filename=$(basename "$line")
    let k="$i%4"
    wait ${children[k]}
    avconv -i "$line" "${filename%.*}.wav" &
    children[k]=$!
    let i++
done

wait ${children[0]}
wait ${children[1]}
wait ${children[2]}
wait ${children[3]}

관련 정보