как условно включить/выключить @echo в командном файле windows?

<p>у меня есть командный файл, который можно запустить локально или на сервере сборки, чтобы сделать какую-то интересную работу. на локальном компьютере я хочу <code>@echo off</code>, чтобы ваша консоль не была полна строк отладки. на сервере сборки я предпочел бы иметь <code>@echo on</code>, чтобы можно было исследовать ошибки.</p><p>контекст сервера сборки можно определить, если существует специальная переменная среды (<code>teamcity\_project\_name</code>). итак, я думал, что мог бы сделать что-то вроде</p><pre><code>if defined teamcity\_project\_name @echo on else @echo off </code></pre><p>но, это не работает, я получаю эхом выражение <code>if</code> вместе со всем остальным ... есть мысли?</p>

<p>на самом деле команда не называется <code>@echo</code>. <code>@</code> является необязательным флагом, действительным в начале оператора, чтобы указать, что эхо подавлено для этого оператора. таким образом, использование <code>@</code> при каждой ссылке на команду <code>echo</code> скрывает саму команду <code>echo</code>, но не предшествующую ей команду <code>if</code>. </p><p>но проблема, которая фактически приводит к тому, что ваша команда не работает должным образом, заключается в том, что первая команда <code>echo</code> будет отбрасывать оставшиеся токены в строке в качестве своих аргументов, поэтому часть <code>else echo off</code> не будет интерпретироваться <code>cmd</code>. поскольку cmd.exe отображает эхо по умолчанию, он печатает команду <code>if</code>, а затем либо выполняет одну команду <code>echo</code>, либо ничего. поскольку <code>@</code> имеет значение в начале оператора, который является телом <code>if</code>, ни одна команда echo не будет напечатана.</p><p>как правило, решение этой проблемы заключается в использовании скобок для разделения границ команд. однако, поскольку echo включен по умолчанию, и вы действительно хотите подавить его, только если <code>teamcity\_project</code> не определен, мы можем сказать это напрямую.</p><pre><code>@if not defined teamcity\_project\_name echo off </code></pre><p>я оставил один <code>@</code> в начале, чтобы подавить эхо этой строки, и в результате эта строка не будет отображаться в журналах вашего сервера.</p><h2>связанное примечание</h2><p>состояние эха также применяется к интерактивному сеансу. ввод <code>echo off</code> в интерактивной подсказке сеанса <code>cmd</code> приведет к тому, что он перестанет отображать подсказку. что немного смущает, если не ожидается. ввод <code>echo on</code> восстановит нормальное поведение.</p><h2>подробнее о разборе</h2><p>(я отредактировал предыдущий раздел для ясности и добавил этот раздел, чтобы попытаться задокументировать, что на самом деле происходит.)</p><p>программа <code>cmd.exe</code>, которая интерпретирует сценарии .bat и .cmd и предоставляет интерактивную команду prompt в современной windows, на удивление хорошо документирована, но при этом фактически не имеет документов. мои попытки найти официальный документ, объясняющий, что знак «at» имеет этот эффект и где именно его можно использовать, в значительной степени не увенчались успехом.</p><p>из экспериментов ясно, что знак at анализируется и интерпретируется, если он появляется как первый непробельный символ команды. я попытался выразить это, используя фразу «начало утверждения» выше. </p><p>насколько я могу судить, не существует формальной грамматики для языка cmd. но мы знаем из документации для самого cdm (типа <code>cmd /?</code> для подсказки), а также <code>if /?</code> и встроенного текста справки для других «интересных» встроенных команд, что существуют правила, которые соблюдаются, когда cmd анализирует свой исходный текст ,.</p><p>начало команды, по-видимому, начинается в начале строки или после условия <code>if</code>, после <code>else</code> или после открытой скобки <code>(</code>. после того, как знак at был распознан, он применяется к (большей части) баланса этой команды.</p><p>попробуйте сами следующий пакетный файл и поиграйте с перемещением знаков «в», и вы быстро поймете, что правила сложно точно сформулировать:</p><pre><code>rem this remark will echo @rem this one will not @ rem neither will this @rem nor this one @rem the if command (and else) will echo, but not either echo command if exist q17241089.bat ( @ echo saw q17241089.bat ) else @ echo foo if not exist q17241089.bat ( @ echo no q17241089.bat ) else @ echo bar @ rem none of the following command is echoed @ if exist q17241089.bat ( @ echo saw q17241089.bat ) else @ echo spam </code></pre><p>при запуске на моем win 7 pro я вижу:</p><pre><code>c...> c...>q17241089.bat c...>rem this remark will echo c...>if exist q17241089.bat () else saw q17241089.bat c...>if not exist q17241089.bat () else bar saw q17241089.bat c...> </code></pre><p>как и в случае с большинством мелких деталей файлов bat, под любой поверхностью, которую вы царапаете, есть загадка.</p>

<p>установить скобки (см. документ ...):</p><pre><code>if defined teamcity\_project\_name (@echo on) else @echo off </code></pre>

<p>похоже, что <code>echo</code> включен по умолчанию, так что вы получите вывод оператора <code>if</code>, когда будете проверять это условие. вы должны начать с</p><pre><code>@echo off </code></pre><p>и добавьте свое условное выражение как другое утверждение для оценки</p><pre><code>@echo off && if defined teamcity\_project\_name @echo on </code></pre>

<p>как отмечалось в предыдущих ответах, echo включено по умолчанию. альтернативный способ достижения того же поведения:</p><pre><code>@if "%teamcity\_project\_name%" == "" @echo off </code></pre>