"시간"에 따라 서브쉘을 조건부로 전달하는 방법은 무엇입니까?

"시간"에 따라 서브쉘을 조건부로 전달하는 방법은 무엇입니까?

개별 단계를 측정하는 데 사용하는 Vagrant 상자용 설정 스크립트가 있습니다 time. 이제 조건부로 시간 측정을 활성화하거나 비활성화하고 싶습니다.

예를 들어 이전 줄은 다음과 같았습니다.

time (apt-get update > /tmp/last.log 2>&1)

이제 다음과 같이 간단히 할 수 있을 것 같습니다.

MEASURE_TIME=true
[[ $MEASURE_TIME = true ]] && TIME="time --format=%e" || TIME=""

$TIME (apt-get update > /tmp/last.log 2>&1)

하지만 이것은 작동하지 않습니다.

syntax error near unexpected token `apt-get'
`$TIME (apt-get update > /tmp/last.log 2>&1)'

여기서 문제가 무엇입니까?

답변1

갈 수 있는 능력이 있다시간필요한 서브쉘time 핵심 단어, 명령이 아닙니다.

키워드는 time언어의 일부이며 문자 그대로 입력하고 명령의 첫 번째 단어로 입력한 경우에만 인식됩니다( 의 경우 ksh93다음 토큰은 로 시작하지 않습니다 -). 말할 것도 없이, 심지어 타이핑도 "time"작동하지 않습니다 (그리고 명령 호출 $TIME로 취급됩니다 ).time

여기서 또 다른 구문 분석 라운드가 수행되기 전에 확장되는 별칭을 사용할 수 있습니다(따라서 쉘이 time키워드를 인식하게 만듭니다).

shopt -s expand_aliases
alias time_or_not=
TIMEFORMAT=%E

MEASURE_TIME=true
[[ $MEASURE_TIME = true ]] && alias time_or_not=time

time_or_not (apt-get update > /tmp/last.log 2>&1)

이것time 핵심 단어옵션은 -p허용되지 않습니다( 제외). 하지만 형식 지정에 변수를 사용할 수 있습니다 bash. (이 부분은 또한 구체적이며 일반적으로 다른 쉘에는 필요하지 않습니다.)TIMEFORMATbashshoptbash

답변2

이는 alias하나의 접근 방식이지만,할 수 있는또한 완료되었습니다 . 명령 실행을 eval원하지 않고 오히려 명령을 원하는 것입니다.evaleval선언.

나는 aliases를 좋아합니다. 항상 사용하지만 함수를 선호합니다. 특히 인수를 처리하는 능력과 aliases처럼 명령 위치에서 확장할 필요가 없다는 점입니다.

그래서 나는 당신도 이것을 시도하고 싶을 것이라고 생각했습니다.

_time() if   set -- "${IFS+IFS=\$2;}" "$IFS" "$@" && IFS='
';      then set -- "$1" "$2" "$*"; unset IFS
             eval "$1 $TIME ${3#"$1"?"$2"?}"
        fi

이 비트 는 $IFS주로 .$*( subshell bit )또한 쉘 확장의 결과따라서 매개변수를 구문 분석 가능한 문자열로 확장하려면"$*" eval "$@"(그런데 모든 인수가 공백으로 연결될 수 있다고 확신하지 않는 한 이 작업을 수행하지 마세요). args in 사이의 구분 기호 "$*"는 의 첫 번째 바이트이므로 $IFS해당 값을 확신하지 않고 진행하는 것은 위험할 수 있습니다. 따라서 함수는 를 저장하고 , 넣을 수 있을 만큼 긴 ewline $IFS으로 설정한 다음 , 이전에 해당 값이 있었다면 해당 값을 재설정합니다.\nset ... "$*""$3"unset

다음은 작은 데모입니다.

TIME='set -x; time'
_time \( 'echo "$(echo any number of subshells)"' \
         'command -V time'                        \
         'hash time'                              \
      \) 'set +x'

알다시피, 나는 두 명령을 모두 값에 넣었습니다 $TIME. 어떤 숫자든 가능합니다. 심지어 없음도 마찬가지입니다. 그러나 인수와 마찬가지로 이스케이프되고 올바르게 인용되었는지 확인하십시오 _time(). 실행될 때 모두 명령 문자열로 연결되지만 각 인수에는 자체 \newline이 있으므로 상대적으로 쉽게 확장할 수 있습니다. 또는 원하는 경우 이를 모두 함께 묶은 다음 \n줄 번호나 세미콜론 등으로 구분할 수 있습니다. 단일 인수가 호출할 때 스크립트의 별도 줄에 안전하게 입력할 수 있는 명령을 나타내는지 확인하세요. \(, 예를 들어 .가 뒤에 오는 한 괜찮습니다 \). 이는 기본적으로 일반적인 것입니다.

eval위의 코드 조각을 얻으면 다음과 같습니다 .

+ eval 'IFS=$2;set -x; time (
echo "$(echo any number of subshells)"
command -V time
hash time
)
set +x'

그리고 결과는 다음과 같습니다.

산출

+++ echo any number of subshells
++ echo 'any number of subshells'
any number of subshells
++ command -V time
time is a shell keyword
++ hash time
bash: hash: time: not found

real    0m0.003s
user    0m0.000s
sys     0m0.000s
++ set +x

오류 는 내가 설치 hash하지 않았음을 나타냅니다./usr/bin/time(나는 그렇지 않기 때문에)command실행되면 알려주세요 . 후행은 set +x실행되는 또 다른 명령입니다.뒤쪽에 time (이것은 가능하다)- 작업을 수행할 때는 항상 명령을 주의 깊게 입력하십시오 eval.

관련 정보