Bash 기능을 실행하기 위해 "at" 명령을 사용할 수 있습니까?

Bash 기능을 실행하기 위해 "at" 명령을 사용할 수 있습니까?

예약된 시간에 Bash 기능을 실행하고 싶습니다. 올바른 도구는 at명령이라고 생각합니다.

그러나 작동하지 않는 것 같습니다.

function stupid () {
    date
}

export -f stupid

cat << EOM | at now + 1 minute
stupid
EOM

잠시 기다린 후 메일을 확인했는데 다음과 같은 오류가 표시되었습니다.

sh: line 41: syntax error near unexpected token `=\(\)\ {\ \ date"
"}'
sh: line 41: `"}; export BASH_FUNC_stupid()'

특히 함수가 작동한다는 것을 알고 있기 때문에 여기서 무엇이 잘못되고 있는지 이해하지 못합니다.

$ stupid
Fri May 29 21:05:38 UTC 2015

오류를 보면 함수를 실행하는 데 잘못된 셸이 사용되고 있는 것 같지만( sh대신 bash), 확인해 보면 $SHELL을 가리키는 것으로 보이며 /bin/bash매뉴얼 페이지에 다음과 at같이 나와 있습니다.

$ echo $SHELL
/bin/bash
$ man at

    ...

    SHELL   The value of the SHELL environment variable at the time
           of at invocation will determine which shell is used  to
           execute  the at job commands.

따라서 Bash는 내 기능을 실행하는 쉘이어야 합니다.

어떻게 되어가나요? 내 Bash 기능을 함께 실행할 수 있는 방법이 있나요 at?

답변1

Bash 기능은 환경을 통해 내보내집니다. 이 at명령은 환경을 재현하는 셸 코드를 생성하여 호출 프로세스의 환경, umask 및 현재 디렉터리를 스크립트에서 사용할 수 있도록 만듭니다. at 작업에서 실행되는 스크립트는 다음과 같습니다.

#!/bin/bash
umask 022
cd /home/nick
PATH=/usr/local/bin:/usr/bin:/bin; export PATH
HOME=/home/nick; export HOME
stupid

()이전 버전의 bash에서는 함수 이름과 함수를 정의한 코드로 시작하고 구성된 값을 포함하는 변수로 함수를 내보냈습니다 .

stupid="() {
    date
}"; export stupid

이로 인해 많은 시나리오가 보안 취약성에 취약해집니다.쉘 쇼크 버그(에서 발견됨스티븐 차제라스)를 사용하면 누구나 어떤 이름으로든 환경 변수의 내용을 주입하여 bash 스크립트에서 임의의 코드를 실행할 수 있습니다. Shellshock 수정 사항이 포함된 bash 버전은 다른 접근 방식을 사용합니다. 이름에 환경 변수에서 찾을 수 없는 문자가 포함된 변수에 함수 정의를 저장하고, 쉘은 이를 할당으로 구문 분석하지 않습니다.

BASH_FUNC_stupid%%="() {
    date
}"; export stupid

이것은 유효한 sh 구문이 아니기 때문에 %bash에서도 at 작업은 함수 사용 시도 여부에 관계없이 실패합니다. 이것at의 데비안 버전는 많은 Linux 배포판에서 사용됩니다.변경됨버전 3.16에서는 셸 스크립트에 유효한 이름이 있는 변수만 내보냅니다. 따라서 at의 최신 버전은 Shellshock 뒤에서 bash를 통해 기능을 내보내지 않지만 이전 버전은 실패합니다.

Shellshock 이전 버전의 bash를 사용하더라도 내보낸 기능은 at 작업 자체가 아닌 at 작업에서 시작된 bash 스크립트 내에서만 작동합니다. at 작업 자체 내에서는 bash에 의해 실행되더라도 stupidbash는 시작 시에만 기능을 가져오는 또 다른 환경 변수입니다.

함수를 at 작업으로 내보내려면(bash 또는 버전에 관계없이) 해당 함수를 파일에 넣고 작업에서 파일을 얻거나 작업에 직접 포함하십시오. 정의된 모든 함수를 읽을 수 있는 형식으로 인쇄하려면 를 사용하십시오 declare -f.

{ declare -f; cat << EOM; } | at now + 1 minute
stupid
EOM

답변2

at/bin/sh대신 사용하도록 설계되었으므로 /bin/bash사용하여 볼 수 있는 코드 서문이 앞에 추가됩니다. 무언가를 연결하여 사용하려면 다음과 같은 간단한 기능을 사용하세요.at -c {jobnumber}bash

at_with_bash_alias_and_functions(){
  ( 
    echo "exec /bin/bash <<END"
    alias
    typeset -f
    cat
    echo END
  ) | sed 's/\$/\\$/g' | at "$@"
}

별칭과 함수가 존재하는지 표시합니다.

at_with_bash_alias_and_functions now <<< "alias;typeset -f"

제한 사항: 인라인 처리는 셸 대체 때문에 구문이 손실될 수 있으며 구문을 검증하는 대신 .uses at처럼 작동합니다 .exec catexec bash

답변3

글쎄, 당신은 이미 우편물을 받게 될 것이라는 것을 알고 있습니다. 멋지다 왜냐하면 넌 절대적으로할 수 있는bash메일이 도착하면 실행되는 함수입니다.

출처 man bash:

  • $MAILPATH

    • 메일을 확인할 파일 이름을 콜론으로 구분한 목록입니다. 메일이 특정 파일에 도착할 때 인쇄할 메시지는 파일 이름과 메시지를 구분하는 구분 기호를 사용하여 지정할 수 있습니다.?. 메시지 텍스트에 사용될 경우 $_현재 메일 파일의 이름으로 확장됩니다. 예:

      MAILPATH='/var/mail/bfox?"You have mail":~/shell-mail?"$_ has mail!"'
      
    • bash이 변수에는 기본값이 제공되지만 사용되는 사용자 메일 파일의 위치는 시스템에 따라 다릅니다.(예를 들어, /var/mail/$USER).

그건 그렇고, $_아니오직이 맥락에서 가능한 확장 - 명령 대체를 포함하여 거의 모든 것을 확장할 수 있습니다. 사실 꼭 그럴 필요는 없지만인쇄아무것. 파일에 반드시 다음이 포함될 필요는 없습니다.우편$MAILCHECK또는 - 쉘은 초당 확인 결과 파일이 마지막으로 본 이후 수정되었음을 나타낼 때 이를 알리려고 시도합니다.

그럼에도 불구하고 쉘이 이를 처리하는 방식은 $MAILxxxx일반적으로 프롬프트에 따라 다릅니다. 즉, $MAILCHECK값에 관계없이 적시에 새 프롬프트를 가져오지 않으면 알림을 받지 못할 것입니다. 다음 프롬프트를 알리기 위해 이를 트리거할 때까지 알림을 받습니다. 이에 대해 잘 모르겠지만 set -b영향을 미칠 수 있습니다.

어쨌든, 이와 같은 작업을 수행하는 방법은 여러 가지가 있습니다. 아마도 가장 확실한 방법은 신호를 사용하여 at작업을 예약하는 것입니다. 예를 들면 다음과 같습니다.

echo kill -USR1 "$$" | at now + 1 minute
trap some_func USR1

무슨 일이 일어나는지 확인하세요.

관련 정보