Як я можу умовно пропустити абонемент через "час"?


9

У мене є сценарій налаштування вікна 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)'

У чому тут проблема?


3
Вам просто потрібно досягти цільової швидкості, щоб конденсатор потоку працював;)
zladilocks

2
@goldilocks Ви маєте на увазі магніт ? ;)
CVn

Відповіді:


13

Для того, щоб бути в змозі тайм подоболочкі, вам потрібно time ключове слово , а не команди.

timeКлючове слово, частина мови, визнаються лише як такі , коли вступили в буквальному сенсі і в якості першого слова команди (і в разі ksh93, то наступна лексема починається не з -). Навіть введення "time"не буде працювати, не кажучи вже про те, $TIMEtimeзамість цього буде прийнято заклик до команди).

Тут ви можете використовувати псевдоніми, які розгортаються до того, як буде проведено черговий раунд розбору (так що оболонка дозволить розпізнати це 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специфічною, інші снаряди, як правило, цього не потребують).


Ви сказали: "Для того, щоб мати змогу запускати передплату, вам потрібно ключове слово". Цікаво, що така поведінка зафіксувала десь?
cuonglm

@cuonglm, див.info -f bash --index-search=time
Stéphane Chazelas

3

Хоча aliasце один із способів зробити це, можна це зробити і за допомогою eval- це просто те, що ви не так сильно хочете виконувати evalкоманду, скільки хочете до оголошенняeval команд .

Мені подобаються aliases - я їх постійно використовую, але мені подобаються функції краще - особливо їх здатність обробляти параметри і що їх не обов’язково розширювати в командному положенні, як це потрібно для aliases.

Тож я подумав, що, можливо, ви також хочете спробувати це:

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

$IFSТрохи в основному про $*. Важливо, що the ( subshell bit )is також є результатом розширення оболонки, і для того, щоб розширити аргументи в простежувану рядок, який я використовую "$*" ( eval "$@"до речі, якщо ви не впевнені, всі аргументи можна з'єднати на пробіли) . Розділювач розділення між аргументами в "$*"- це перший байт $IFS, тому продовжувати його можна, не визначаючи його значення. Таким чином, функція зберігає $IFS, встановлює його в \newline досить довго , щоб 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, і тому їх можна буде розповсюдити порівняно легко. Або ж ви можете згрупувати їх усі за одне, якщо вам подобається, і розділити їх на \newlines або напівколонки або що-у вас є. Просто переконайтеся, що один аргумент являє собою команду, якій вам буде зручно вводити свій власний рядок у сценарій, коли ви викликаєте його. \(, наприклад, це добре, якщо з часом його слідкують \). В основному нормальні речі.

Коли 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чого-небудь.


Якась причина цього не зробити _time() { eval "$TIME $@"; }? Використання функції має недолік, коли вводиться інша область для змінних (не проблема для
підшлунків

@ StéphaneChazelas - через цитати в "$@"розширенні. Мені подобається один аргумент eval- інакше стає страшно. Уммм .... як ви хочете сказати про різні сфери застосування? Я думав, що це лише functionфункції ...
mikeserv

evalприєднується до своїх аргументів перед тим, як виконати, що саме ви намагаєтеся зробити дуже перекрученим способом. Я мав на увазі, що _time 'local var=1; blah'це зробить varлокальне для цього _time, або те, що _time 'echo "$#"'буде надрукувати $#цю _timeфункцію, а не функцію абонента.
Стефан Шазелас

@ StéphaneChazelas - У мене тут є два вкладки. Право - evalконцентрує свої аргументи на просторах - це, як ви кажете, саме те, що я роблю тут, - хоча це не було первинним наміром. Я збираюся це виправити. evalНа "$*"відміну від "$@"звички, яку я взяв після багатьох command not foundнабігів, коли аргументи були об'єднані в неправильному місці. У будь-якому випадку, хоча аргументи в кінцевому рахунку виконуються у функції, я думаю, досить просто розгорнути їх при виклику. Це те, що я б робив з "$#"будь-яким.
mikeserv

+1 за приємний кручений шматок хакеру, хоча ...
Stéphane Chazelas
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.