Cách ghi đè cùng một dòng trong đầu ra lệnh từ tệp bó


13

Tôi muốn viết một số thông tin trạng thái thay thế dòng cuối cùng khi tôi làm một cái gì đó.

Trong ví dụ về tập tin bat, tôi muốn văn bản Step 2ghi đè lên Step 1cùng một dòng trong đầu ra lệnh.

echo off

echo Step 1
REM Do some stuff...

echo Step 2
REM do some other stuff...

Câu trả lời:


8

Kịch bản này sẽ làm chính xác những gì bạn yêu cầu:

@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...

Tôi tìm thấy câu trả lời này bằng cách xem mã trong một thư viện thao tác ký tự tập lệnh được viết bởi Dave Benham có tên là CharLib .

Thư viện này có thể tạo tất cả các ký tự trong phạm vi 1..255.

Để biết thêm thông tin, hãy xem chủ đề có tên "Có thể chuyển đổi một ký tự thành giá trị ASCII của nó không?"

Chỉnh sửa 2017-4-26: Có vẻ như đoạn mã trên không còn hoạt động . Tôi không chắc chắn khi hành vi này sẽ thay đổi, nhưng nó chắc chắn được sử dụng để làm việc. Các CRnhân vật sau khi =bị tước setlệnh. Ah, nó dường như là một sự thay đổi trong cách setlàm việc giữa XP và các phiên bản Windows mới hơn. Xem câu trả lời xuất sắc trong dòng Ghi đè trong tệp bó Windows? (trùng lặp) để biết thêm chi tiết và thêm ví dụ mã.

Sau đó, một cách khác là đặt một ký tự không phải khoảng trắng trước !ASCII_13!và sắp xếp để xóa nó, có lẽ bằng cách chèn một khoảng trống (không bị xóa) theo sau là khoảng trắng hoặc bằng cách thêm khoảng trắng vào cuối chuỗi dấu nhắc (không bị tước.)

Ví dụ như thế này:

@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...

2
Đối với tôi, điều này chỉ in "Bước 1Bước 2" thay vì chỉ có "Bước 2" trên màn hình.
galmok

@galmok này đã bắt đầu xảy ra với tôi quá, nhưng tôi chắc chắn rằng nó không bao giờ dùng đến (như tôi có một kịch bản được sử dụng để làm việc một cách hoàn hảo đặt thời gian gần đây đã thay đổi đến hành vi bạn mô tả.) Có vẻ như các setlệnh tại dải bất kỳ Các ký tự CR và LF (cũng như khoảng trắng) sau =. Hãy thử đặt một ký tự không phải khoảng trắng giữa =!ACSII_13!
timfoden

Có một cách để làm tất cả những điều này ... Tôi thực sự đã đến để xem liệu có ai khác nhận thấy không, bởi vì tôi muốn xem liệu họ có phát hiện ra nó đã đi được bao xa không. ... Tôi có thể viết TRẢ LỜI trên stack stack không? HAY .. như một câu hỏi và trả lời ngay lập tức? Tôi cho rằng tôi có thể viết nó dưới dạng câu hỏi về những gì bạn có thể làm với nó .. Tôi đã phải đi ăn gì đó nhưng tôi sẽ cập nhật điều này với một liên kết cho bạn.
Brent Rittenhouse

Viết! ASCII_13! sau Bước 1 để ngăn chặn tước, vì vậy ở bước 2, bạn sẽ mã hóa:set /p "=Step 2 " <NUL
Zimba

6

Để trả lời câu hỏi:

@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

Đầu ra:

End

Về cơ bản, những gì kịch bản thực hiện, là viết Step 1, sau đó quay ngược lại một nơi, ghi đè 1, và cuối cùng đi hoàn toàn trở lại và ghi đè Step 2với End.

Điều này quay trở lại tôi làm với ký tự ASCII 8 đặc biệt là backspace. Vì tôi không biết cách viết nó trong cmd, tôi sử dụng hàm: EVALUATE chạy hàm VBS Chr () và đặt ký tự backspace vào biến result. Nếu ai đó biết một cách tốt hơn, xin vui lòng tư vấn.


1
Trong PowerShell, bạn cũng có thể lưu trữ $host.ui.RawUI.CursorPositionvào một biến và khôi phục nó sau để con trỏ quay trở lại vị trí của bạn và ghi đè đầu ra của bạn. Chỉ là một tùy chọn cho PowerShell, nhưng có thể sạch hơn một chút so với công cụ VBS của bạn :-)
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

GIẢI TRÌNH:

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

điều này sẽ đặt ký tự backspace thành biến BSPACE. Bây giờ để xem kết quả, gõ:

echo ab%BSPACE%c

đầu ra: ac

bạn có thể sử dụng biến BSPACE này nhiều lần để xóa nhiều ký tự.

Bây giờ, nếu bạn muốn đặt lợi nhuận vận chuyển trong một biến, hãy sử dụng

for /F "usebackq" %%a in (sao chép / Z "% ~ dpf0" nul) DO (set "cr=%%a")

để xem kết quả, gõ: setlocal EnableDelayedExpansion & echo asfasdhlfashflkashflksa!CR!***

đầu ra sẽ là: ***asfasdhlfashflkashflksa

Câu trả lời của @ davour ở trên cũng rất hay nhưng câu trả lời của @ timfoden không phù hợp với tôi.


Câu trả lời của @ timfoden không hoạt động vì! CR! nên đi ở cuối bước trước. Ngoài ra, thay vì tất cả% BSPACE% s, bạn cũng có thể! CR! và điền vào chỗ trắng:set /p "=.!CR!End. " <NUL&echo:
Zimba

3

Bạn không thể. Thông thường, bạn có thể đạt được loại điều này bằng cách bao gồm ký tự trả về vận chuyển (0x0D) trong tệp sẽ đưa con trỏ trở lại cột đầu tiên trong cùng một dòng. Nhưng trong trường hợp này nó không hoạt động; CR chỉ âm thầm ăn.

Hơn nữa, việc đưa CR vào đó khá khó khăn và ít nhất ở đây có sự tham gia của một trình soạn thảo văn bản. Tôi khuyên bạn nên viết một chương trình tiện ích nhỏ sẽ làm điều này cho bạn, nó thực sự không khó lắm. Chương trình C nhỏ sau đây có thể đủ (nếu bạn không cần Unicode):

#include <stdio.h>

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

Nó không làm gì khác hơn là in một ký tự CR và sau đó là văn bản bạn chỉ định làm đối số đầu tiên. Cách sử dụng như sau:

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

Dòng cuối cùng là cuộc gọi đến chương trình đó. Dòng thứ hai là thành ngữ lô bình thường để in văn bản mà không bị ngắt dòng (điều này rất quan trọng trong trường hợp này vì nếu không bạn không thể ghi đè lên dòng). Bạn cũng có thể sử dụng chương trình ở trên cũng như ở nơi đó.

Một cách nhẹ nhàng, nhưng cách duy nhất mà bạn có thể chắc chắn nơi bạn kết thúc, sẽ là sử dụng clstrước bước đầu ra của bạn. Sẽ nhấp nháy nhưng theo cách đó bạn luôn viết cho phía trên bên trái. Và ghi đè mọi thứ có thể nhìn thấy trong bảng điều khiển (đó là lý do tại sao tôi không khuyên dùng nó); hầu hết người dùng không thích điều đó quá nhiều.


OK, tôi đã có một nghi ngờ rằng nó không thể thực hiện được với dòng lệnh sạch. Nếu tôi muốn làm cho một tiện ích làm điều này, tôi cũng có thể đặt toàn bộ điều đó vào một tiện ích. Điều tôi thực sự muốn chỉ là đếm ngược hiển thị, chờ 5 giây, đếm ngược từng giây cho đến khi hoàn thành.
kinh hoàng

4
awe: Nếu bạn đang dùng Vista trở lên, thì nó timeout 5sẽ hoạt động.
Joey

Tuyệt quá! cảm ơn bạn! hết thời gian 5 công trình!
kinh hoàng

4
Lẽ ra tôi nên gửi Vấn đề thực sự của tôi lần đầu tiên ...
kinh sợ

Tất nhiên bạn có thể; chỉ cần thêm trở lại vận chuyển sau bước 1! Hơn nữa, đây là một số mã để lấy lại vận chuyển mà không cần có trình soạn thảo văn bản:for /f %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
Zimba

1

Nhận ký tự dòng mới, viết bước tiếp theo, quay lại bắt đầu dòng, viết dòng tiếp theo:

@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.

Điều này sẽ chỉ hoạt động nếu Step 1 Step 2 Step 3tất cả đều có cùng chiều dài. Nếu không phải là văn bản đầu tiên set /pvẫn còn. Không chắc chắn làm thế nào để khắc phục điều này.
Ste

Vấn đề đó có thể được khắc phục bằng cách sử dụng các ký tự khoảng trắng bổ sung trong dấu nhắc tiếp theo. để bao gồm bất kỳ nhân vật trước. Ví dụ set /p "=Step 2SPACESPACESPACESPACE!Newline!" <NUL trái ngược với set /p "=Step 2!Newline!" <NUL. Trao đổi SPACEcho nhân vật.
Ste

Nếu các dòng trước dài hơn, sau đó thêm khoảng trắng để xóa các ký tự phụ hoặc xóa lùi từ cuối dòng đến đầu hoặc chỉ xóa lùi cho các ký tự phụ.
Zimba

0

Bạn sẽ cần một thư viện con trỏ màn hình như curseshoặc ncurses, nhưng tôi không quá quen thuộc với việc sử dụng chúng. Cả hai thư viện đều được phát triển cho các hệ thống Unix, nhưng bạn có thể tìm thấy chúng cho Windows (trong môi trường Cygwin , hoặc GnuWin32 ).

Tôi không biết bất kỳ cách dễ dàng nào để truy cập chúng trong tệp bó kiểu DOS. Bạn có thể tốt hơn hết là lập trình bằng một ngôn ngữ được biên dịch. Hãy xem Ncurses HOWTO để có ý tưởng tốt hơn về việc nó sẽ hữu ích.


lời nguyền là khá nhiều cho các thiết bị đầu cuối và trình giả lập thiết bị đầu cuối. Họ không thực sự ánh xạ tới API bảng điều khiển gốc của Windows.
Joey

KHÔNG cần thư viện bên ngoài; hoạt động tốt với các công cụ CMD.
Zimba

0

Giải pháp 1

Với Notepad ++ , có thể chèn Backspace ←trực tiếp ký tự (ASCII 0x08) bằng cách sử dụng Bảng chèn mã ASCII (Chỉnh sửa> Bảng ký tự).

Giải pháp của tôi là chèn [BS]ký tự trực tiếp và sau đó, giống như các giải pháp khác được đăng ở đây, sử dụng nó nhiều lần để xóa các ký tự trước đó:

@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

Ảnh chụp màn hình Notepad ++

Ghi đè hàng loạt Windows


Đầu ra

Đầu ra CMD


Giải pháp 2

Một khả năng khác là sử dụng cecho (lệnh echo có hỗ trợ màu sắc) để chèn một Carriage Return ↵ký tự unicode (U + 000D):

@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

NB: cecho_x64.exechạy nhanh hơn đáng kể trên máy của tôi hơn cecho.exe.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.