Windows-эквивалент echo -n больше не работает в Win7

У меня был отличный трюк в Windows cmd.exe (по крайней мере, до XP), чтобы эмулировать поведение эха UNIX без новой строки, echo -n. Например, команда:

<nul: set /p junk= xyzzy

приведет к выводу ровно шести символов, начального пробела и строки «xyzzy», и ничего больше.

Если вам интересно, почему это работает, на самом деле это команда ввода, которая выводит " xyzzy" в качестве подсказки, а затем ожидает ввода пользователем, прежде чем назначить этот ввод переменной среды junk. В этом конкретном случае он не ожидает ввода данных пользователем, поскольку он получает ввод с устройства nul.

Это было довольно полезно в сценариях cmd, когда (например) обработка файлов в цикле (одна итерация на файл), когда вы хотите перечислить более одного файла в строке. Используя этот трюк, вы можете просто выводить каждое имя файла, за которым следует пробел и без новой строки, а затем, после цикла, выводить новую строку для завершения:

Processing files:
    file1.txt file42.txt p0rn.zip

Теперь я обнаружил, что в Windows 7 пробелы больше не выводятся, поэтому я получаю следующее:

Processing files:
file1.txtfile42.txtp0rn.zip

Есть ли способ заставить set /p снова начать соблюдать мои пробелы, или в Win7 есть другой способ добиться того же эффекта?

Я пробовал цитировать, используя . (который работает в echo) и даже экранировал строку с помощью ^, но ни один из них не работает:

C:\Pax> <nul: set /p junk= xyzzy
xyzzy

C:\Pax> <nul: set /p junk=" xyzzy"
xyzzy

C:\Pax> <nul: set /p junk=' xyzzy'
' xyzzy'

C:\Pax> <nul: set /p junk=. xyzzy
. xyzzy

C:\Pax> <nul: set /p junk=^ xyzzy
xyzzy

Мне нужно:

C:\Pax> some_magical_command_with_an_argument xyzzy
 xyzzy

что даст мне пробел(ы) в начале и без новой строки в конце.


person paxdiablo    schedule 05.04.2013    source источник
comment
+1 за попытку ДЕЙСТВИТЕЛЬНО усердно делать в пакетных файлах то, что любой здравомыслящий человек делал бы в PERL или PYTHON.   -  person Warren P    schedule 05.04.2013
comment
@Warren, к сожалению, политика диктует, что мы можем использовать только то, что доступно при базовой установке Win. Итак, Perl и Python отсутствуют, несмотря на то, что я, вероятно, мог бы сделать это в половине строки кода :-) Я мог бы переписать скрипты на VBScript, но я надеюсь на более простое исправление - скрипты не маленькие. Сказав это, я мог бы просто сделать эхо-бит в VBS, чтобы я мог изучить это. Если вы укажете это в ответе, я поставлю вам +1, поскольку именно ваш комментарий об использовании приличного языка заставил меня так думать.   -  person paxdiablo    schedule 05.04.2013
comment
Значит, ваша компания не разрешает людям устанавливать программы с помощью установщика? :-)   -  person Warren P    schedule 05.04.2013
comment
@Warren: не совсем так, мы можем установить все, что захотим, если это одобрено законом и не подключено к основной сети. Однако этот сценарий отправляется клиентам, которые, скорее всего, не согласятся установить Python/Perl.   -  person paxdiablo    schedule 05.04.2013
comment
Даже Microsoft FixIt являются EXE-файлами. Просто создайте небольшой EXE. Вы знаете, как это сделать?   -  person Warren P    schedule 05.04.2013
comment
@ Уоррен, это ответ, а не комментарий. Подмигнуть, подмигнуть, подмигнуть :-)   -  person paxdiablo    schedule 05.04.2013
comment
Этот вопрос фактически уже вызывалась. Я предполагаю, что частью ответа на ваш вопрос будет отсутствие простого (т.е. одной команды) решения в пакетном режиме.   -  person Andriy M    schedule 05.04.2013
comment
@Warren P: ПОЧЕМУ ты ОРЁШЬ СЛУЧАЙНЫЕ СЛОВА и ИМЕНА ЗАГЛАВНЫМИ БУКВАМИ?   -  person BoltClock    schedule 05.04.2013
comment
Это похоже на то, что нужно делать, когда речь идет о пакетных файлах DOS. :-)   -  person Warren P    schedule 05.04.2013
comment
@WarrenP: Для акцента курсив или жирный шрифт мне показались бы более обычными, чем ВСЕ ЗАГЛАВНЫЕ, хотя и не так удобно.   -  person Andriy M    schedule 07.04.2013
comment
Дело принято. Как сделать курсив в комментарии? О, смотрите, я разобрался.   -  person Warren P    schedule 07.04.2013
comment
Вау, я как раз собирался предложить JScript, а потом прокрутил вниз, лол.   -  person user541686    schedule 28.04.2013


Ответы (4)


Это очень похоже на ответ paxdiablo, за исключением того, что я использую гибридный JScript/пакетный файл вместо временного файла VBScript.

Мой сценарий называется jEval.bat, и он просто оценивает любое допустимое выражение JScript и записывает результат в стандартный вывод, необязательно с завершающей новой строкой. Этот глупый маленький скрипт чрезвычайно полезен для пакетного программирования.

Предполагая, что jEval.bat находится либо в вашей текущей папке, либо где-то в вашем PATH, вы можете просто сделать что-то вроде:

call jeval "' xyzzy'"

Вот сценарий. Это действительно очень просто. Большая часть кода связана с документацией, обработкой ошибок и встроенной справочной системой.

@if (@X)==(@Y) @end /* harmless hybrid line that begins a JScrpt comment

::************ Documentation ***********
:::
:::jEval  JScriptExpression  [/N]
:::jEval  /?
:::
:::  Evaluates a JScript expression and writes the result to stdout.
:::
:::  A newline (CR/LF) is not appended to the result unless the /N
:::  option is used.
:::
:::  The JScript expression should be enclosed in double quotes.
:::
:::  JScript string literals within the expression should be enclosed
:::  in single quotes.
:::
:::  Example:
:::
:::    call jEval "'5/4 = ' + 5/4"
:::
:::  Output:
:::
:::    5/4 = 1.25
:::

::************ Batch portion ***********
@echo off

if "%~1" equ "" (
  call :err "Insufficient arguments"
  exit /b
)
if "%~2" neq "" if /i "%~2" neq "/N" (
  call :err "Invalid option"
  exit /b
)
if "%~1" equ "/?" (
  setlocal enableDelayedExpansion
  for /f "delims=" %%A in ('findstr "^:::" "%~f0"') do (
    set "ln=%%A"
    echo(!ln:~3!
  )
  exit /b
)
cscript //E:JScript //nologo "%~f0" %*
exit /b

:err
>&2 echo ERROR: %~1. Use jeval /? to get help.
exit /b 1


************ JScript portion ***********/
if (WScript.Arguments.Named.Exists("n")) {
  WScript.StdOut.WriteLine(eval(WScript.Arguments.Unnamed(0)));
} else {
  WScript.StdOut.Write(eval(WScript.Arguments.Unnamed(0)));
}
person dbenham    schedule 07.04.2013

Это не использует set или другие cmd-внутренние вещи, но вы можете использовать cscript (также включенный в стандартную установку Windows), чтобы сделать то же самое. Вы даже можете управлять им из самого файла cmd (не нужно поддерживать отдельные файлы), используя создание временных файлов vbs.

Поместите этот код в свой файл cmd:

rem Create the VBS file to output spaces and a word.

echo.for i = 1 to WScript.Arguments.Item(0) >spacetext.vbs
echo.     WScript.StdOut.Write ^" ^" >>spacetext.vbs
echo.next >>spacetext.vbs
echo.WScript.StdOut.Write WScript.Arguments.Item(1) >>spacetext.vbs

rem Do this once per word you want output (eg, in a loop).

cscript /nologo spacetext.vbs 0 Hello,
cscript /nologo spacetext.vbs 1 my
cscript /nologo spacetext.vbs 1 name
cscript /nologo spacetext.vbs 1 is
cscript /nologo spacetext.vbs 4 Pax.

rem Do this at the end to add newline and kill temp file.

echo.
del spacetext.vbs

Результатом этого является то, что вы ожидаете:

Hello, my name is    Pax.
person paxdiablo    schedule 05.04.2013

Вы имеете в виду вот так?

@ECHO OFF
SETLOCAL
FOR /l %%i IN (1,1,4) DO <NUL SET /p var="item %%i "

Результат:

пункт 1 пункт 2 пункт 3 пункт 4

Или вы абсолютно настаиваете на пробеле в начале?

person Magoo    schedule 05.04.2013

Хорошо, теперь есть правильный ответ: у вас не может быть ведущего <space> в Win7 с set /p. Существуют различия между версиями Windows:

Syntax                |  XP                                 |  Vista and Windows 7
----------------------+-------------------------------------+-------------------------------------
<nul set /p =!msg!    |- If 1st char is quote, then trims   |- Trims leading white space chars.   
       or             |  that quote, and if at least one    |- If 1st non white space char is     
<nul set /p "=!msg!"  |  additional quote, than trims last  |  quote, then that quote is treated  
                      |  quote and all remaining chars.     |  as white space and trimmed, and if
                      |- If 1st non trimmed char is =, then |  at least one additional quote, then
                      |  syntax error.                      |  trims last quote and all remaining
                      |                                     |  chars.
                      |                                     |- If 1st non trimmed char is =, then
                      |                                     |  syntax error.
----------------------+-------------------------------------+-------------------------------------
<nul set /p ="!msg!"  |- Trims leading control chars and    |- Trims leading white space chars.
       or             |  spaces.                            |- If 1st non trimmed char is =, then 
<nul set /p "="!msg!""|- If 1st non trimmed char is =, then |  syntax error.
                      |  syntax error.                      |
----------------------+-------------------------------------+-------------------------------------

On Vista and Windows 7, the trimmed leading white space chars are:
    9  0x09  Horizontal Tab
   10  0x0A  New Line
   11  0x0B  Vertical Tab
   12  0x0C  Form Feed
   13  0x0D  Carriage Return
   32  0x20  Space
  255  0xFF  Non-breaking Space

источник

О другом методе получения ведущих пробелов в чистом пакете см. здесь

person Endoro    schedule 05.04.2013