개별 단계를 측정하는 데 사용하는 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
. (이 부분은 또한 구체적이며 일반적으로 다른 쉘에는 필요하지 않습니다.)TIMEFORMAT
bash
shopt
bash
답변2
이는 alias
하나의 접근 방식이지만,할 수 있는또한 완료되었습니다 . 명령 실행을 eval
원하지 않고 오히려 명령을 원하는 것입니다.eval
eval
선언.
나는 alias
es를 좋아합니다. 항상 사용하지만 함수를 선호합니다. 특히 인수를 처리하는 능력과 alias
es처럼 명령 위치에서 확장할 필요가 없다는 점입니다.
그래서 나는 당신도 이것을 시도하고 싶을 것이라고 생각했습니다.
_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
으로 설정한 다음 , 이전에 해당 값이 있었다면 해당 값을 재설정합니다.\n
set ... "$*"
"$3"
unset
다음은 작은 데모입니다.
TIME='set -x; time'
_time \( 'echo "$(echo any number of subshells)"' \
'command -V time' \
'hash time' \
\) 'set +x'
알다시피, 나는 두 명령을 모두 값에 넣었습니다 $TIME
. 어떤 숫자든 가능합니다. 심지어 없음도 마찬가지입니다. 그러나 인수와 마찬가지로 이스케이프되고 올바르게 인용되었는지 확인하십시오 _time()
. 실행될 때 모두 명령 문자열로 연결되지만 각 인수에는 자체 \n
ewline이 있으므로 상대적으로 쉽게 확장할 수 있습니다. 또는 원하는 경우 이를 모두 함께 묶은 다음 \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
.