Lote de Windows: echo sin nueva línea


231

¿Cuál es el equivalente por lotes de Windows del comando de shell de Linux echo -nque suprime la nueva línea al final de la salida?

La idea es escribir en la misma línea dentro de un bucle.



2
esto me volvió casi loco ... Sabía que echopodría soportarlo, -npero cmd.exeno funcionaría ^^
panny

11
@panny: a pesar del nombre común, echo no es el mismo comando entre Windows y Posix. Al igual que nslookup, tiene diferentes opciones. Entonces, el comentario "Sabía que echopodría tomar -n" en el contexto de una pregunta relacionada con Windows, es incorrecto.
user66001

Respuestas:


236

Usando sety el /pparámetro que puede hacer eco sin nueva línea:

C:\> echo Hello World
Hello World

C:\> echo|set /p="Hello World"
Hello World
C:\>

Fuente


86
La tubería es muy lenta ya que crea dos cmd-tareas adicionales, más rápido es <nul set /p =Hello. set /pno puede hacer eco de un signo igual como primer carácter ni espacios / pestañas.
jeb

11
Es casi 15 veces más rápido en mi sistema
jeb

28
Agregue citas alrededor de "Hello World" para evitar el espacio extraño después del d.
Brian

13
Advertencia: Esto cambiará ERRORLEVEL a 1. Vea la respuesta de @xmechanix.
CoperNick

66
@ user246694 < nules una redirección desde el NULdispositivo. No contiene nada, pero eso es suficiente para set /pdejar de esperar la entrada del usuario
jeb

100

Usando: echo | set /p=o<NUL set /p= ambos funcionarán para suprimir la nueva línea.

Sin embargo, esto puede ser muy peligroso cuando se escriben scripts más avanzados cuando se comprueba que ERRORLEVEL se vuelve importante como configuración set /p= sin especificar un nombre de variable establecerá ERRORLEVEL en 1.

Un mejor enfoque sería usar un nombre de variable ficticio como este:
echo | set /p dummyName=Hello World

Esto producirá exactamente lo que desea sin que ocurra ninguna cosa furtiva en segundo plano, ya que tuve que averiguarlo de la manera difícil, pero esto solo funciona con la versión canalizada; <NUL set /p dummyName=Helloaún elevará el ERRORLEVEL a 1.


20
Advertencia: Este comando establecerá ERRORLEVEL en 0. Si ERRORLEVEL fue mayor que 0, cambiará ERRORLEVEL a 0. Esto también puede ser peligroso al escribir scripts más avanzados. (pero +1 por respuesta)
CoperNick

Entonces, básicamente, necesita un IF ERRORLEVEL == 0 (...) ELSE (...) simplemente para no dañar su entorno en esas circunstancias. Sheesh
SilverbackNet

28

El método SET / P simple tiene limitaciones que varían ligeramente entre las versiones de Windows.

  • Las comillas principales pueden ser despojadas

  • El espacio en blanco inicial puede ser eliminado

  • El inicio =provoca un error de sintaxis.

Consulte http://www.dostips.com/forum/viewtopic.php?f=3&t=4209 para obtener más información.

jeb publicó una solución inteligente que resuelve la mayoría de los problemas en Texto de salida sin salto de línea, incluso con espacio inicial o = He refinado el método para que pueda imprimir de manera segura absolutamente cualquier cadena de lote válida sin la nueva línea, en cualquier versión de Windows desde XP en adelante. Tenga en cuenta que el:writeInitialize método contiene un literal de cadena que puede no publicarse bien en el sitio. Se incluye una observación que describe cuál debería ser la secuencia de caracteres.

Los métodos :writey :writeVarestán optimizados de modo que solo las cadenas que contienen caracteres iniciales problemáticos se escriben usando mi versión modificada del método COPY de jeb. Las cadenas no problemáticas se escriben utilizando el método SET / P más simple y rápido.

@echo off
setlocal disableDelayedExpansion
call :writeInitialize
call :write "=hello"
call :write " world!%$write.sub%OK!"
echo(
setlocal enableDelayedExpansion
set lf=^


set "str= hello!lf!world^!!!$write.sub!hello!lf!world"
echo(
echo str=!str!
echo(
call :write "str="
call :writeVar str
echo(
exit /b

:write  Str
::
:: Write the literal string Str to stdout without a terminating
:: carriage return or line feed. Enclosing quotes are stripped.
::
:: This routine works by calling :writeVar
::
setlocal disableDelayedExpansion
set "str=%~1"
call :writeVar str
exit /b


:writeVar  StrVar
::
:: Writes the value of variable StrVar to stdout without a terminating
:: carriage return or line feed.
::
:: The routine relies on variables defined by :writeInitialize. If the
:: variables are not yet defined, then it calls :writeInitialize to
:: temporarily define them. Performance can be improved by explicitly
:: calling :writeInitialize once before the first call to :writeVar
::
if not defined %~1 exit /b
setlocal enableDelayedExpansion
if not defined $write.sub call :writeInitialize
set $write.special=1
if "!%~1:~0,1!" equ "^!" set "$write.special="
for /f delims^=^ eol^= %%A in ("!%~1:~0,1!") do (
  if "%%A" neq "=" if "!$write.problemChars:%%A=!" equ "!$write.problemChars!" set "$write.special="
)
if not defined $write.special (
  <nul set /p "=!%~1!"
  exit /b
)
>"%$write.temp%_1.txt" (echo !str!!$write.sub!)
copy "%$write.temp%_1.txt" /a "%$write.temp%_2.txt" /b >nul
type "%$write.temp%_2.txt"
del "%$write.temp%_1.txt" "%$write.temp%_2.txt"
set "str2=!str:*%$write.sub%=%$write.sub%!"
if "!str2!" neq "!str!" <nul set /p "=!str2!"
exit /b


:writeInitialize
::
:: Defines 3 variables needed by the :write and :writeVar routines
::
::   $write.temp - specifies a base path for temporary files
::
::   $write.sub  - contains the SUB character, also known as <CTRL-Z> or 0x1A
::
::   $write.problemChars - list of characters that cause problems for SET /P
::      <carriageReturn> <formFeed> <space> <tab> <0xFF> <equal> <quote>
::      Note that <lineFeed> and <equal> also causes problems, but are handled elsewhere
::
set "$write.temp=%temp%\writeTemp%random%"
copy nul "%$write.temp%.txt" /a >nul
for /f "usebackq" %%A in ("%$write.temp%.txt") do set "$write.sub=%%A"
del "%$write.temp%.txt"
for /f %%A in ('copy /z "%~f0" nul') do for /f %%B in ('cls') do (
  set "$write.problemChars=%%A%%B    ""
  REM the characters after %%B above should be <space> <tab> <0xFF>
)
exit /b

1
Es bueno ver una solución muy poderosa que puede manejar todos los personajes
jeb

2
Me gustaría señalar que si la computadora tiene una conexión de red a Internet, aproximadamente esta cantidad de código de lote se puede usar para descargar e instalar Python o cualquier otra cosa en la computadora que pueda eliminarlo. Batch es divertido, sin embargo, sus capacidades de cadena son mejores para el desafío de fin de semana.
n611x007

@dbenham en la línea 6 "echo (" es funcionalmente lo mismo que "echo" - no lo había visto antes.
Saltar R

2
@SkipR: Sí, es funcionalmente igual que ECHO., excepto que ECHO.puede fallar en circunstancias oscuras . Hay un montón de otras formas que también pueden fallar en situaciones oscuras. El único que siempre funciona es ECHO(.
dbenham

10

Como un apéndice a la respuesta de @xmechanix, noté al escribir el contenido en un archivo:

echo | set /p dummyName=Hello World > somefile.txt

Que esto agregará un espacio adicional al final de la cadena impresa , lo que puede ser un inconveniente, especialmente porque estamos tratando de evitar agregar una nueva línea (otro carácter de espacio en blanco) al final de la cadena.

Afortunadamente, citando la cadena a imprimir, es decir, usando:

echo | set /p dummyName="Hello World" > somefile.txt

Imprimirá la cadena sin ningún carácter de nueva línea o espacio al final.


55
El espacio extra debería desaparecer si no coloca un espacio entre Worldy >...
aschipfl

@aschipfl Probado, no lo hace.
Joan Bruguera

El método de variables citadas, una característica no documentada del comando set, es generalmente como veo que debe abordarse, ya que funciona en todas las versiones de Windows NT (y 9x si recuerdo). Es decir, ajusta el nombre de la variable al final del valor entre comillas. Esto también es cierto para Set / P.
Ben Personick

1
IE: echo | set / p "dummyName = Hello World"> somefile.txt
Ben Personick

2
@aschipfl Aparecerá un espacio extra si no haces comillas y haces una tubería. xxd es una utilidad de volcado hexadecimal, por lo que vemos, por ejemplo, set /p="abc"<nul|xxd -ppantallas 616263 mientras que set /p=abc<nul|xxd -pda61626320
barlop

9

Una solución para el espacio en blanco eliminado en SET / P:

El truco es ese carácter de retroceso que puede invocar en el editor de texto EDITAR para DOS. Para crearlo en EDITAR, presione ctrlP + ctrlH . Lo pegaría aquí, pero esta página web no puede mostrarlo. Sin embargo, es visible en el Bloc de notas (es angosto, como un pequeño rectángulo negro con un círculo blanco en el centro)

Entonces escribes esto:

<nul set /p=.9    Hello everyone

El punto puede ser cualquier carácter, solo está ahí para decirle a SET / P que el texto comienza allí, antes de los espacios, y no en el " Hola ". El " 9 " es una representación del carácter de retroceso que no puedo mostrar aquí. Debe ponerlo en lugar del 9, y eliminará el " . ", Después de lo cual obtendrá esto:

    Hello Everyone

en vez de:

Hello Everyone

Espero que ayude


2
Olvidé decir que funciona en Windows 7. No funcionará en una línea de comando, solo en un lote. Para cualquiera que no obtenga el char, descargue este ejemplo: pecm.com.sapo.pt/SET_with_backspace_char.txt
Pedro

También es cierto para Echo
Ben Personick

... Entonces, después de hacer una búsqueda bastante minuciosa, no he encontrado esto EN CUALQUIER LUGAR en la red. Puede ser la única vez que descubrí algo, y por suerte. Para aquellos que no saben, PUEDES ingresar caracteres de control si pones tu cmd prompt en modo heredado y usas la fuente correcta. ... Pero si simplemente redirige cualquier cosa a un archivo o> con, también funciona. Seriamente. Pegue esto EXACTAMENTE en el símbolo del sistema: "echo ← c◙◙ ○○ Harharhar !! ◙ ○○ ------------- ◙◙ ○○ ¡Soy el peor!?: '(○ ♪ ○ ¡NO! • ♪ ○ ¡Me siento genial! ¡Hazzah-le-oop! ◙◙ ○ Soy programador, escúchame ... algo.◙> con ".
Brent Rittenhouse

Bien, espero haberlo descubierto antes que nadie pero ... esto aparentemente depende de no estar en una página de códigos Unicode. Puede almacenar el inicio en una variable do chcp 437, establecer el conjunto en una variable o generarlo, y luego cambiar de nuevo (y aún debería generar). Todavía estoy jugando con eso.
Brent Rittenhouse

Además, ¿alguien tiene alguna idea de por qué ← c borra la pantalla? No puedo encontrar una instancia de eso en ninguna parte de la red. Es específicamente esa combinación, aunque parece que también puedes tener espacios en blanco entre los dos caracteres. Para cualquier otro personaje, parece simplemente ... eliminar el primer personaje. No lo entiendo ...
Brent Rittenhouse

7

Puede eliminar la nueva línea usando "tr" de gnuwin32 ( paquete coreutils )

@echo off
set L=First line
echo %L% | tr -d "\r\n"
echo Second line
pause

Por cierto, si está haciendo muchos scripts, gnuwin32 es una mina de oro.


También sugiero instalar git bash . seguro que no es lo mismo que gnuwin32 (y es una mina de oro, por lo tanto, +1), es solo una buena configuración, y tiene git-bash en el botón derecho del mouse en casi todas partes, incluido el botón del menú de inicio.
Hakre

¿Puedes usar tr para eliminar el último carácter de espacio, como en trim?
panny

use sed para recortar: sed -e "s / * $ //"
BearCode

@panny: no puedo encontrar una utilidad posix / linux llamada trim. También, \r, \no \r\n(Nuevas líneas en OSX, POSIX y Windows respectivamente) no son caracteres "espacio".
user66001

5

Aquí hay otro método, utiliza Powershell Write-Host que tiene un parámetro -NoNewLine, combina eso start /by ofrece la misma funcionalidad de lote.

NoNewLines.cmd

@ECHO OFF
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 1 - ';Write-Host -NoNewLine 'Result 2 - ';Write-Host -NoNewLine 'Result 3 - '"
PAUSE

Salida

Result 1 - Result 2 - Result 3 - Press any key to continue . . .

Este a continuación es ligeramente diferente, no funciona exactamente como quiere el OP, pero es interesante porque cada resultado sobrescribe el resultado anterior emulando un contador.

@ECHO OFF
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 1 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 2 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 3 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 4 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 5 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 6 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 7 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 8 - '"
start /b /wait powershell.exe -command "Write-Host -NoNewLine 'Result 9 - '"
PAUSE


2

Tal vez esto es lo que estás buscando, es un guión de la vieja escuela ...: P

set nl=^& echo. 
echo %nl%The%nl%new%nl%line%nl%is%nl%not%nl%apparent%nl%throughout%nl%text%nl%
echo only in prompt.
pause

o tal vez estás tratando de reemplazar una línea actual en lugar de escribir en una nueva línea? puedes experimentar con esto eliminando el "% bs%" después del "." firmar y también espaciando el otro "% bs%" después del "Mensaje de ejemplo".

for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "bs=%%a"
<nul set /p=.%bs%         Example message         %bs%
pause

Encuentro esto realmente interesante porque usa una variable para un propósito diferente al que está destinado a hacer. como puede ver, "% bs%" representa un retroceso. El segundo "% bs%" usa el espacio de retroceso para agregar espacios después del "Mensaje de ejemplo" para separar la "Salida del comando Pausa" sin agregar realmente un carácter visible después del "Mensaje de ejemplo". Sin embargo, esto también es posible con un signo de porcentaje regular.


2
Veo este set nl=^& echo.truco en todas partes y el nombre de la variable es engañoso. % nl% no es un carácter de nueva línea : se expande a &echo.fin de que al final ejecute un nuevo echocomando cada vez, de ahí la nueva línea. Puedes verlo por escrito echo "%nl%The%nl%new%nl%line%nl%is%nl%not%nl%apparent%nl%throughout%nl%text%nl%". Obtienes "& echo. The& echo. new& echo. line& echo. is& echo. not& echo. apparent& echo. throughout& echo. text& echo. ", revelando el truco. El resultado es el mismo, pero no por las razones que sugiere.
cdlvcdlv

2

cw.exeUtilidad de bricolaje (escritura de consola)

Si no lo encuentra listo para usar, listo para usar, puede hacer bricolaje. Con esta cwutilidad puedes usar todo tipo de personajes. Al menos, me gustaría pensar que sí. Por favor, pruébelo y hágamelo saber.

Herramientas

Todo lo que necesitas es .NET instalado, que es muy común hoy en día.

Materiales

Algunos caracteres escritos / copiados.

Pasos

  1. Crea un .batarchivo con el siguiente contenido.
/* >nul 2>&1

@echo off
setlocal

set exe=cw
for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d  /o:-n "%SystemRoot%\Microsoft.NET\Framework\*csc.exe"') do set "csc=%%v"

"%csc%" -nologo -out:"%exe%.exe" "%~f0"

endlocal
exit /b %errorlevel%

*/

using System;

namespace cw {
    class Program {
        static void Main() {
            var exe = Environment.GetCommandLineArgs()[0];
            var rawCmd = Environment.CommandLine;
            var line = rawCmd.Remove(rawCmd.IndexOf(exe),exe.Length).TrimStart('"');
            line = line.Length < 2 ? "\r" : line.Substring(2) ;
            Console.Write(line);
        }
    }
}
  1. Ejecutarlo.

  2. Ahora tiene una buena utilidad de 4KB para que pueda eliminar el .bat.

Alternativamente, puede insertar este código como una subrutina en cualquier lote, enviar el resultado .exea %temp%, usarlo en su lote y eliminarlo cuando haya terminado.

Cómo utilizar

Si quieres escribir algo sin nueva línea:
cw Whatever you want, even with "", but remember to escape ^|, ^^, ^&, etc. unless double-quoted, like in "| ^ &".

Si desea un retorno de carro (yendo al principio de la línea), ejecute solo
cw

Así que intente esto desde la línea de comando:

for /l %a in (1,1,1000) do @(cw ^|&cw&cw /&cw&cw -&cw&cw \&cw)

Tu respuesta me inspiró y creé esta pequeña herramienta con Go y esta tarea complementaria para Azure Pipelines. Simplemente toma el stdout que se canaliza y lo genera en un formato específico para que la compilación lo recoja. ¡Gracias!
riezebosch

2

Hice una función de la idea de @arnep:

echo | set / p = "Hola mundo"

aquí está:

:SL (sameline)
echo|set /p=%1
exit /b

Úselo con call :SL "Hello There"
Sé que esto no es nada especial, pero me tomó tanto tiempo pensar en eso que pensé que lo publicaría aquí.


1

Muestra 1: esto funciona y produce el código de salida = 0. Eso es bueno. Nota la "." , directamente después del eco.

C: \ Users \ phife.dog \ gitrepos \ 1 \ repo_abc \ scripts #
@echo. | set / p JUNK_VAR = Este es un mensaje que se muestra como Linux echo -n lo mostraría ... & echo% ERRORLEVEL%

Este es un mensaje mostrado como Linux echo -n lo mostraría ... 0

Muestra 2: esto funciona pero produce el código de salida = 1. Eso es malo. Tenga en cuenta la falta de ".", Después del eco. Esa parece ser la diferencia.

C: \ Users \ phife.dog \ gitrepos \ 1 \ repo_abc \ scripts #
@echo | set / p JUNK_VAR = Este es un mensaje que se muestra como Linux echo -n lo mostraría ... & echo% ERRORLEVEL%

Este es un mensaje que se muestra como Linux echo -n lo mostraría ... 1


1

Inspirado por las respuestas a esta pregunta, hice un simple script de contador de lotes que sigue imprimiendo el valor de progreso (0-100%) en la misma línea (sobrescribiendo el anterior). Tal vez esto también sea valioso para otros que buscan una solución similar.

Observación : *son caracteres no imprimibles, estos deben ingresarse utilizando la combinación de teclas [ Alt+ Numpad 0+ Numpad 8], que es el backspacecarácter.

@ECHO OFF

FOR /L %%A in (0, 10, 100) DO (     
    ECHO|SET /P="****%%A%%"    
    CALL:Wait 1
)

GOTO:EOF

:Wait
SET /A "delay=%~1+1"
CALL PING 127.0.0.1 -n %delay% > NUL
GOTO:EOF

0

Creo que no hay tal opción. Alternativamente, puedes probar esto

set text=Hello
set text=%text% world
echo %text%

3
Esto todavía imprimirá una nueva línea.
René Nyffenegger

3
Puede concatenar en la misma variable todo lo que desee y solo hacer eco al final.
m0skit0

2
Imprimirlo al hacer el bucle o al final no importa si se conservan los datos. Para cada ciclo, solo concatena los datos y, cuando finaliza el ciclo, los imprime. El resultado es el mismo.
m0skit0

99
Que no importa si es un indicador de la progresión del ciclo.
Gregreg

3
Nunca dijo eso en su pregunta ni solicitó este comportamiento en ninguna parte de su pregunta.
m0skit0

0

Puede suprimir la nueva línea utilizando el comando set / p. El comando set / p no reconoce un espacio, para eso puede usar un punto y un carácter de retroceso para que lo reconozca. También puede usar una variable como memoria y almacenar lo que desea imprimir en ella, para que pueda imprimir la variable en lugar de la oración. Por ejemplo:

@echo off
setlocal enabledelayedexpansion
for /f %%a in ('"prompt $H & for %%b in (1) do rem"') do (set "bs=%%a")
cls
set "var=Hello World! :)"
set "x=0"

:loop
set "display=!var:~%x%,1!"
<nul set /p "print=.%bs%%display%"
ping -n 1 localhost >nul
set /a "x=%x% + 1"
if "!var:~%x%,1!" == "" goto end
goto loop

:end
echo.
pause
exit

De esta forma, puede imprimir cualquier cosa sin una nueva línea. He hecho el programa para imprimir los caracteres uno por uno, pero también puedes usar palabras en lugar de caracteres cambiando el bucle.

En el ejemplo anterior utilicé "enabledelayedexpansion" para que el comando set / p no reconozca "!" carácter e imprime un punto en lugar de eso. Espero que no tengas el uso del signo de exclamación "!" ;)


-1

Respuesta tardía aquí, pero para cualquier persona que necesite escribir caracteres especiales en una sola línea que encuentre que la respuesta de dbenham es aproximadamente 80 líneas demasiado larga y cuyos guiones pueden romperse (quizás debido a la entrada del usuario) bajo las limitaciones de simplemente usar set /p, Probablemente sea más fácil emparejar su .bat o .cmd con un ejecutable en lenguaje C ++ o C y luego solo couto printflos caracteres. Esto también le permitirá escribir fácilmente varias veces en una línea si está mostrando una especie de barra de progreso o algo con caracteres, como aparentemente lo hizo OP.


@jiggunjer ¿Estás seguro? printfing desde un cmdpanel Win-7 me da"'printf' is not recognized as an internal or external command, operable program or batch file."
SeldomNeedy

printfNo es nativo de Windows. Esta es una pregunta de Windows.
kayleeFrye_onDeck

1
@kayleeFrye_onDeck Asumo que tu comentario está dirigido a jiggunjer , no a mí; Sugiero en mi pregunta que C y C ++ podrían usarse como una alternativa bastante independiente de la plataforma a los comandos de shell en los casos en que el formato es importante.
SeldomNeedy

1
Perdóname padre, porque me he desnatado.
kayleeFrye_onDeck

Pero entonces la entrada al shell debe analizarse correctamente. Por ejemplo, ¿cómo imprimiría un programa de este tipo una comilla?
Alex
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.