Jak zastąpić ten sam wiersz w danych wyjściowych polecenia z pliku wsadowego

13

Chcę napisać informacje o statusie, które zastępują ostatni wiersz, gdy coś robię.

W poniższym przykładowym pliku nietoperza chcę Step 2nadpisać tekst Step 1w tym samym wierszu wyniku polecenia.

echo off

echo Step 1
REM Do some stuff...

echo Step 2
REM do some other stuff...
groza
źródło

Odpowiedzi:

8

Ten skrypt zrobi dokładnie to, o co prosiłeś:

@echo off

setlocal enableextensions enabledelayedexpansion
for /f %%a in ('copy /Z "%~dpf0" nul') do set "ASCII_13=%%a"

set /p "=Step 1" <NUL
REM Do some stuff...

set /p "=!ASCII_13!Step 2" <NUL
REM do some other stuff...

Znalazłem tę odpowiedź, patrząc na kod w bibliotece do manipulacji znakami skryptów wsadowych napisanej przez Dave'a Benhama o nazwie CharLib .

Ta biblioteka jest w stanie utworzyć wszystkie znaki z zakresu 1..255.

Aby uzyskać więcej informacji, zobacz temat zatytułowany „Czy można przekonwertować znak na jego wartość ASCII?”

Edytuj 2017-4-26: Wygląda na to, że powyższy kod już nie działa . Nie jestem pewien, kiedy to zachowanie by się zmieniło, ale na pewno zadziałało. CRZnak po =teraz zostaje pozbawiony przez setkomendę. Ach, wydaje się, że jest to zmiana w sposobie setdziałania między XP a nowszymi wersjami systemu Windows. Widzisz doskonałą odpowiedź w wierszu Zastąp w pliku wsadowym systemu Windows? (duplikat), aby uzyskać więcej szczegółów i dodatkowe przykłady kodu.

Alternatywą jest zatem umieszczenie przed spacją znaku spacji !ASCII_13!i ustawienie go również do usunięcia, być może albo przez wstawienie spacji (która nie jest usuwana), a następnie spacji lub przez dodanie spacji na końcu ciąg zachęty (który nie jest usuwany).

Np. Tak:

@echo off

setlocal enableextensions enabledelayedexpansion
for /f %%a in ('copy /Z "%~dpf0" nul') do set "ASCII_13=%%a"

set /p "=Step 1" <NUL
REM Do some stuff...

set /p "=x!ASCII_13!Step 2 " <NUL
REM do some other stuff...
timfoden
źródło
2
Dla mnie to po prostu drukuje „Krok 1 Krok 2” zamiast tylko „Krok 2” na ekranie.
galmok
@galmok To też zaczęło mi się przydarzyć, ale jestem pewien, że nigdy tak nie było (ponieważ mam skrypt, który działał doskonale, ostatnio został zmieniony na opisywane zachowanie). Wygląda na to, że setpolecenie teraz usuwa Znaki CR i LF (oraz spacje) po =. Spróbuj =!ACSII_13!
wstawić
Jest na to sposób ... Przyszedłem sprawdzić, czy ktoś to zauważył, bo chciałem sprawdzić, czy odkryli, jak daleko to się posunęło. ... Czy mogę napisać ODPOWIEDŹ w przypadku przepełnienia stosu? LUB .. lubisz pytanie i od razu na nie odpowiadasz? Przypuszczam, że mógłbym napisać w formie pytania o to, co możesz z tym zrobić. Muszę coś zjeść, ale zaktualizuję to, podając Ci link.
Brent Rittenhouse
Napisz! ASCII_13! po kroku 1, aby zapobiec zdejmowaniu izolacji, więc w kroku 2 należy set /p "=Step 2 " <NUL
napisać
6

Aby odpowiedzieć na pytanie:

@echo off
CALL :EVALUATE "chr(8)"
SET backspace=%result%
<nul set /p =Step 1
:: DO SOME STUFF....
<nul set /p =%backspace%
<nul set /p =2
:: DO SOME OTHER STUFF....
<nul set /p =%backspace%%backspace%%backspace%%backspace%%backspace%%backspace%
<nul set /p =End   
GOTO:EOF



:EVALUATE           -- evaluate with VBS and return to result variable
::                  -- %~1: VBS string to evaluate
:: extra info: http://groups.google.com/group/alt.msdos.batch.nt/browse_thread/thread/9092aad97cd0f917

@IF [%1]==[] ECHO Input argument missing & GOTO :EOF 

@ECHO wsh.echo "result="^&eval("%~1") > %temp%\evaluate_tmp_67354.vbs 
@FOR /f "delims=" %%a IN ('cscript //nologo %temp%\evaluate_tmp_67354.vbs') do @SET "%%a" 
@DEL %temp%\evaluate_tmp_67354.vbs
::ECHO %result%
@GOTO:EOF

Wynik:

End

Zasadniczo, co robi skrypt, to pisze Step 1, a następnie cofa się o jedno miejsce nadpisuje 1, a na końcu przechodzi całkowicie do tyłu i nadpisuje Step 2z End.

Wracając, robię to ze specjalnym znakiem ASCII 8, którym jest backspace. Ponieważ nie wiem, jak napisać to w cmd, używam funkcji: EVALUATE, która uruchamia funkcję VBS Chr () i wstawia znak backspace do zmiennej result. Jeśli ktoś zna lepszy sposób, proszę o poradę.

Davor Josipovic
źródło
1
W programie PowerShell można również zapisać $host.ui.RawUI.CursorPositionzmienną i przywrócić ją później, aby kursor przeskoczył z powrotem do miejsca, w którym się znajdowałeś, i zastąpić dane wyjściowe. Tylko opcja dla PowerShell, ale może być nieco czystsza niż twoje VBS :-)
mihi
4
@echo off
for /F "tokens=1 delims=# " %%a in ('"prompt #$H# & echo on & for %%b in (1) do rem"') do set "BSPACE=%%a"
<nul set /p =Step 1
ping 127.0.0.1 >nul
<nul set /p =%BSPACE%
<nul set /p =2
ping 127.0.0.1 >nul
<nul set /p =%BSPACE%
<nul set /p =3
ping 127.0.0.1 >nul
<nul set /p =%BSPACE%%BSPACE%%BSPACE%%BSPACE%%BSPACE%%BSPACE%
<nul set /p =End.  
pause

WYJAŚNIENIE:

for /F "tokens=1 delims=# " %%a in ('"prompt #$H# & echo on & for %%b in (1) do rem"') do set "BSPACE=%%a"

ustawi to znak backspace w zmiennej BSPACE. Teraz, aby zobaczyć wynik, wpisz:

echo ab%BSPACE%c

wynik: ac

możesz użyć tej zmiennej BSPACE więcej niż jeden raz, aby usunąć wiele znaków.

Teraz, jeśli chcesz ustawić powrót karetki w zmiennej, użyj

for /F "usebackq" %%a in (copy / Z "% ~ dpf0" nul) DO (set "cr=%%a")

aby zobaczyć wynik, wpisz: setlocal EnableDelayedExpansion & echo asfasdhlfashflkashflksa!CR!***

wyjście będzie: ***asfasdhlfashflkashflksa

Powyższa odpowiedź @ davour jest również piękna, ale odpowiedź @ timfoden nie zadziałała dla mnie.

Sourav Ghosh
źródło
Odpowiedź @ timfoden nie zadziałała, ponieważ! CR! powinien przejść na koniec poprzedniego kroku. Ponadto zamiast wszystkich tych% BSPACE% s, możesz także! CR! i wypełnij spacjami:set /p "=.!CR!End. " <NUL&echo:
Zimba,
3

Nie możesz Zazwyczaj można to osiągnąć, umieszczając w pliku znak powrotu karetki (0x0D), który umieści kursor z powrotem w pierwszej kolumnie w tym samym wierszu. Ale w tym przypadku to nie działa; CR jest po prostu zjadany w ciszy.

Ponadto uzyskanie CR jest tam trochę trudne i przynajmniej w tym przypadku zaangażowany jest edytor tekstu. Sugeruję napisanie małego programu narzędziowego, który zrobi to za Ciebie, w rzeczywistości nie jest to bardzo trudne. Następujący mały program C może wystarczyć (jeśli nie potrzebujesz Unicode):

#include <stdio.h>

int main(int argc, char* argv[]) {
  if (argc < 2) return 1;
  printf("\r%s", argv[1]);
}

Nie robi nic poza drukowaniem znaku CR, a następnie tekstu, który podajesz jako pierwszy argument. Zastosowanie w następujący sposób:

@echo off
<nul set /P X=Step 1
pause>nul 2>nul
over.exe "Step 2"

Ostatnia linia to wywołanie tego programu. Druga linia to zwykły idiom wsadowy do drukowania tekstu bez końcowego podziału linii (co jest ważne w tym przypadku, ponieważ w przeciwnym razie nie można nadpisać linii). Jednak równie dobrze możesz użyć powyższego programu w tym miejscu.

Lekko zhackowany sposób, ale jedynym, w którym możesz być pewien, gdzie skończysz, będzie użycie clsprzed wyjściem z kroku. Migocze, ale w ten sposób zawsze piszesz w lewym górnym rogu. I spychaj wszystko, co było widoczne w konsoli (dlatego nie polecałbym tego); większość użytkowników nie lubi tego zbytnio.

Joey
źródło
OK, podejrzewałem, że nie można zrobić z czystą linią poleceń. Jeśli chcę, aby narzędzie to robiło, równie dobrze mogę umieścić całą rzecz w narzędziu. Naprawdę chciałem tylko widoczne odliczanie, które czeka 5 sekund, odliczając każdą sekundę do zakończenia.
respekt
4
awe: jeśli korzystasz z systemu Vista lub nowszego, timeout 5będzie działać.
Joey,
Świetny! Dziękuję Ci! Limit czasu 5 działa!
awe
4
Powinienem był opublikować mój prawdziwy problem za pierwszym razem ...
podziw
Oczywiście, że możesz; po prostu dodaj zwrot karetki po kroku 1! Ponadto, oto kod, aby uzyskać zwrot karetki bez angażowania edytora tekstu:for /f %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
Zimba
1

Uzyskaj znak nowej linii, napisz następny krok, wróć na początek linii, napisz następny wiersz:

@echo off
cls
setlocal enabledelayedexpansion
echo Here's how it's done:

for /f %%a in ('copy /Z "%~f0" nul') do set "Newline=%%a"
set /p "=Step 1!Newline!" <NUL
REM Do some stuff...
ping -n 2 localhost > nul
set /p "=Step 2!Newline!" <NUL
ping -n 2 localhost > nul
set /p "=Step 3 " <NUL
REM do some other stuff...
ping -n 2 localhost > nul
echo:
echo Done.
Zimba
źródło
Działa to tylko wtedy, gdy Step 1 Step 2 Step 3wszystkie są tej samej długości. Jeśli nie, tekst pierwszego set /ppozostaje. Nie jestem pewien, jak to naprawić.
Ste
Ten problem można rozwiązać, używając dodatkowych znaków spacji w następnym monitie. na pokrycie wszystkich poprzednich znaków. Przykład set /p "=Step 2SPACESPACESPACESPACE!Newline!" <NUL w przeciwieństwie do set /p "=Step 2!Newline!" <NUL. Wymień się SPACEna postać.
Ste
Jeśli poprzednie wiersze są dłuższe, dodaj spacje, aby usunąć dodatkowe znaki, lub cofnij od końca wiersza do początku lub po prostu cofnij do dodatkowych znaków.
Zimba
0

Potrzebna byłaby biblioteka kursora ekranowego, taka jak curseslub ncurses, ale nie jestem zbyt obeznana z ich użyciem. Obie biblioteki zostały opracowane dla systemów uniksowych, ale można je znaleźć dla systemu Windows (w środowisku Cygwin lub GnuWin32 ).

Nie znam żadnego łatwego sposobu na dostęp do nich w pliku wsadowym w stylu DOS. Lepiej jest programować w skompilowanym języku. Spójrz na Ncurses HOWTO, aby dowiedzieć się, czy będzie przydatny.

quack quixote
źródło
przekleństwa są w zasadzie tylko dla terminali i emulatorów terminali. Naprawdę nie mapują do natywnego interfejsu API konsoli Windows.
Joey,
NIE ma potrzeby korzystania z bibliotek zewnętrznych; działa dobrze z narzędziami CMD.
Zimba
0

Rozwiązanie 1

W Notepad ++ można bezpośrednio wstawić Backspace ←znak (ASCII 0x08), korzystając z panelu wstawiania kodów ASCII (Edycja> Panel znaków).

Moim rozwiązaniem jest wstawienie [BS]znaku bezpośrednio, a następnie, podobnie jak inne opublikowane tutaj rozwiązania, użyj go wiele razy, aby usunąć poprzednie znaki:

Kod

@ECHO OFF

SET "BACKSPACE_x7=[BS][BS][BS][BS][BS][BS][BS]"

SET /P "DUMMY_VAR=Step 1" < NUL
REM Do some stuff...

SET /P "DUMMY_VAR=%BACKSPACE_x7%Step 2" < NUL
REM Do some other stuff...

GOTO :EOF

Zrzut ekranu Notepad ++

Zastąpienie wsadowe systemu Windows


Wynik

Wyjście CMD


Rozwiązanie 2

Inną możliwością jest użycie cechyo (polecenie echa z obsługą kolorów), aby wstawić Carriage Return ↵znak Unicode (U + 000D):

Kod

@ECHO OFF

SET CARRIAGE_RETURN={\u000D}

cecho Step 1
REM Do some stuff...

cecho %CARRIAGE_RETURN%Step 2
REM Do some other stuff...

GOTO :EOF

Uwaga: cecho_x64.exedziała na mojej maszynie znacznie szybciej niż cecho.exe.

andronoid
źródło