sleep 명령없이 bash에서 바쁜 대기를 피하십시오. 수 있었다. while true; do

나는 bash에서 다음과 같이하면 조건이 충족되기를 기다릴 수 있다는 것을 안다.

while true; do
  test_condition && break
  sleep 1
done

그러나 각 반복마다 하나의 하위 프로세스를 만듭니다 (슬립). 나는 그렇게함으로써 그들을 피할 수 있었다.

while true; do
  test_condition && break
done

그러나 그것은 많은 CPU를 사용합니다 (바쁨 대기). 하위 프로세스와 바쁜 대기를 피하기 위해 솔루션 벨로우즈를 생각해 냈지만 추악합니다.

my_tmp_dir=$(mktemp -d --tmpdir=/tmp)    # Create a unique tmp dir for the fifo.
mkfifo $my_tmp_dir/fifo                  # Create an empty fifo for sleep by read.
exec 3<> $my_tmp_dir/fifo                # Open the fifo for reading and writing.

while true; do
  test_condition && break
  read -t 1 -u 3 var                     # Same as sleep 1, but without sub-process.
done

exec 3<&-                                # Closing the fifo.
rm $my_tmp_dir/fifo; rmdir $my_tmp_dir   # Cleanup, could be done in a trap.

참고 : 일반적인 경우, 나는 read -t 1 varstdin을 소비하고 stdin이 터미널이나 파이프가 아닌 경우 작동하지 않기 때문에 fifo없이 간단히 사용할 수 없습니다 .

하위 프로세스와 더 우아한 방식으로 바쁜 대기를 피할 수 있습니까?



답변

최신 버전 bash(최소 v2)에서는 내장을로드 할 수 있습니다 (enable -f filename commandname 을 런타임에 . 로드 가능한 많은 내장 기능도 bash 소스와 함께 배포되며 그 sleep중 하나입니다. 물론 가용성은 OS마다 다를 수 있으며 심지어 기계마다 다를 수 있습니다. 예를 들어, openSUSE에서 이러한 내장은 package를 통해 배포됩니다 bash-loadables.

편집 : 패키지 이름을 수정하고 최소 bash 버전을 추가하십시오.


답변

많은 하위 프로세스를 만드는 것은 내부 루프에서 나쁜 것입니다. sleep초당 하나의 프로세스를 작성 해도됩니다. 아무 문제 없어

while ! test_condition; do
  sleep 1
done

실제로 외부 프로세스를 피하려면 fifo를 열어 둘 필요가 없습니다.

my_tmpdir=$(mktemp -d)
trap 'rm -rf "$my_tmpdir"' 0
mkfifo "$my_tmpdir/f"

while ! test_condition; do
  read -t 1 <>"$my_tmpdir/f"
done


답변

나는 최근에 이것을 할 필요가 있었다. 외부 프로그램을 호출하지 않고 bash가 영원히 잠들 수있게하는 다음 기능을 생각해 냈습니다.

snore()
{
    local IFS
    [[ -n "${_snore_fd:-}" ]] || { exec {_snore_fd}<> <(:); } 2>/dev/null ||
    {
        # workaround for MacOS and similar systems
        local fifo
        fifo=$(mktemp -u)
        mkfifo -m 700 "$fifo"
        exec {_snore_fd}<>"$fifo"
        rm "$fifo"
    }
    read ${1:+-t "$1"} -u $_snore_fd || :
}

참고 : 이전에 파일 설명자를 열고 닫을 수있는 버전을 게시했지만 일부 시스템 에서이 작업을 수백 번 수행하면 결국 잠길 수 있습니다. 따라서 새로운 솔루션은 함수를 호출 할 때마다 파일 디스크립터를 유지합니다. Bash는 어쨌든 종료시 정리합니다.

이것은 / bin / sleep처럼 호출 될 수 있으며 요청 된 시간 동안 휴면 상태가됩니다. 매개 변수없이 호출하면 영원히 중단됩니다.

snore 0.1  # sleeps for 0.1 seconds
snore 10   # sleeps for 10 seconds
snore      # sleeps forever

내 블로그에 과도한 세부 정보가있는 글이 있습니다.


답변

에서 ksh93또는 mksh, sleep쉘 내장은, 대안은 대신 그 쉘을 사용하는 것이 될 수 있도록bash .

zsh또한 을 사용하여 지정된 수백 초 동안 잠을 잘 수 있는 zselect내장 (으로로드 zmodload zsh/zselect) 기능이 있습니다 zselect -t <n>.


답변

사용자 yoi가 말했듯이 스크립트에서 stdin이 열리면 sleep 1 대신 다음을 사용할 수 있습니다.

read -t 1 3<&- 3<&0 <&3

Bash 버전 4.1 이상에서는 float 숫자를 사용할 수 있습니다. read -t 0.3 ...

스크립트에서 stdin 이 닫히면 ( 스크립트 가라고my_script.sh < /dev/null &) 다른 열린 디스크립터를 사용해야 합니다. 예를 들어 읽기 를 실행할 때 출력을 생성하지 않습니다 . 표준 출력 :

read -t 1 <&1 3<&- 3<&0 <&3

스크립트에서 모든 디스크립터가 닫히면 ( stdin , stdout , stderr ) (예 : 데몬이라고 함) 출력을 생성하지 않는 존재하는 파일을 찾아야합니다.

read -t 1 </dev/tty10 3<&- 3<&0 <&3


답변

이것은 비대화 형 쉘뿐만 아니라 로그인 쉘에서도 작동합니다.

#!/bin/sh

# to avoid starting /bin/sleep each time we call sleep, 
# make our own using the read built in function
xsleep()
{
  read -t $1 -u 1
}

# usage
xsleep 3


답변

당신은 정말로 fifo가 필요합니까? stdin을 다른 파일 디스크립터로 리디렉션하는 것도 효과적입니다.

{
echo line | while read line; do
   read -t 1 <&3
   echo "$line"
done
} 3<&- 3<&0

고무시키는 : while 루프 안에서 bash에서 입력 읽기