कमांड लाइन को कैसे चेतन करें?


80

मैंने हमेशा सोचा है कि लोग कमांड लाइन में पिछली लाइन को कैसे अपडेट करते हैं। इसका एक बड़ा उदाहरण है जब linux में wget कमांड का उपयोग करना। यह एक ASCII लोडिंग बार बनाता है जो इस तरह दिखता है:

[======>] ३>%

और निश्चित रूप से लोडिंग बार चलता है और प्रतिशत बदलता है, लेकिन यह एक नई रेखा नहीं बनाता है। मैं यह पता नहीं लगा सकता कि यह कैसे करना है। क्या कोई मुझे सही दिशा दिखा सकता है?

जवाबों:


46

मुझे ऐसा करने के दो तरीके हैं:

  • अपनी रेखा को मिटाने के लिए बैकस्पेस एस्केप कैरेक्टर ('\ b') का उपयोग करें
  • cursesपैकेज का उपयोग करें , यदि आपकी पसंद की प्रोग्रामिंग भाषा में इसके लिए बाइंडिंग है।

और Google ने ANSI एस्केप कोड्स का खुलासा किया , जो एक अच्छा तरीका है। संदर्भ के लिए, यहाँ ऐसा करने के लिए C ++ में एक फ़ंक्शन है:

void DrawProgressBar(int len, double percent) {
  cout << "\x1B[2K"; // Erase the entire current line.
  cout << "\x1B[0E"; // Move to the beginning of the current line.
  string progress;
  for (int i = 0; i < len; ++i) {
    if (i < static_cast<int>(len * percent)) {
      progress += "=";
    } else {
      progress += " ";
    }
  }
  cout << "[" << progress << "] " << (static_cast<int>(100 * percent)) << "%";
  flush(cout); // Required.
}

7
यह मानते हुए कि वह Windows (यानी 2000+) के हालिया संस्करण पर Win32 कंसोल ऐप (DOS नहीं) चला रहा है, ANSI एस्केप कोड बिल्कुल भी काम नहीं करेगा। जैसा कि आप से जुड़े विकिपीडिया लेख में कहा गया है।
ह्यूग एलन

अगर आप विंडोज पर ANSI एस्केप सीक्वेंस के साथ काम कर रहे हैं, तो आप अंसिकॉन का उपयोग कर सकते हैं। github.com/adoxa/ansicon
Jens A. Koch

58

ऐसा करने का एक तरीका वर्तमान प्रगति के साथ पाठ की रेखा को बार-बार अपडेट करना है। उदाहरण के लिए:

def status(percent):
    sys.stdout.write("%3d%%\r" % percent)
    sys.stdout.flush()

ध्यान दें कि मैंने sys.stdout.writeइसके बजाय print(यह पायथन है) का उपयोग किया है क्योंकि printप्रत्येक पंक्ति के अंत में स्वचालित रूप से "\ r \ n" (गाड़ी-वापसी नई-लाइन) प्रिंट करता है। मैं बस गाड़ी-वापसी चाहता हूं जो लाइन की शुरुआत में कर्सर लौटाता है। इसके अलावा, flush()यह आवश्यक है क्योंकि डिफ़ॉल्ट रूप से, sys.stdoutकेवल एक नई लाइन के बाद (या इसके बफर पूर्ण होने के बाद) अपने आउटपुट को फ्लश करता है।


और प्रिंटफ और 'आर' के साथ 'सी' में भी ऐसा ही है।
डेविड एल मॉरिस

जब तक एक नई पंक्ति (\ n) नहीं लिखी जाती है तब तक @Nearoo सामान्य रूप से अपने आउटपुट को रोक देता है। निस्तब्धता आंशिक रेखा को तुरंत प्रकट करती है।
ग्रेग हेविगिल

21

गुप्त लाइन के \ n या \ r \ n के बजाय केवल \ r प्रिंट करना है।

\ r को कैरेज रिटर्न कहा जाता है और यह लाइन की शुरुआत में कर्सर ले जाता है

\ n को लाइन फ़ीड कहा जाता है और यह कंसोल में अगली लाइन पर कर्सर ले जाता है। यदि आप केवल \ r का उपयोग करते हैं तो आप पहले से लिखी गई लाइन को ओवरराइट कर देते हैं। तो पहले निम्नलिखित की तरह एक पंक्ति लिखें:

[          ]

फिर प्रत्येक टिक के लिए एक संकेत जोड़ें

\r[=         ]

\r[==        ]

...

\r[==========]

और इसी तरह। आप 10 वर्णों का उपयोग कर सकते हैं, प्रत्येक 10% का प्रतिनिधित्व करते हैं। इसके अलावा, यदि आप एक संदेश प्रदर्शित करना चाहते हैं, तो समाप्त होने पर, पर्याप्त सफेद वर्ण जोड़ना न भूलें ताकि आप पहले से लिखे समान संकेतों को इस तरह से लिख दें:

\r[done      ]

1
यह काम किया, पूरी तरह से। यह मेरी राय में बहुत आसान है।
Erutan409

4

नीचे मेरा जवाब है, विंडोज़ एपीआई कंसोल (विंडोज) , सी की कोडिंग का उपयोग करें।

/*
* file: ProgressBarConsole.cpp
* description: a console progress bar Demo
* author: lijian <hustlijian@gmail.com>
* version: 1.0
* date: 2012-12-06
*/
#include <stdio.h>
#include <windows.h>

HANDLE hOut;
CONSOLE_SCREEN_BUFFER_INFO bInfo;
char charProgress[80] = 
    {"================================================================"};
char spaceProgress = ' ';

/*
* show a progress in the [row] line
* row start from 0 to the end
*/
int ProgressBar(char *task, int row, int progress)
{
    char str[100];
    int len, barLen,progressLen;
    COORD crStart, crCurr;
    GetConsoleScreenBufferInfo(hOut, &bInfo);
    crCurr = bInfo.dwCursorPosition; //the old position
    len = bInfo.dwMaximumWindowSize.X;
    barLen = len - 17;//minus the extra char
    progressLen = (int)((progress/100.0)*barLen);
    crStart.X = 0;
    crStart.Y = row;

    sprintf(str,"%-10s[%-.*s>%*c]%3d%%", task,progressLen,charProgress, barLen-progressLen,spaceProgress,50);
#if 0 //use stdand libary
    SetConsoleCursorPosition(hOut, crStart);
    printf("%s\n", str);
#else
    WriteConsoleOutputCharacter(hOut, str, len,crStart,NULL);
#endif
    SetConsoleCursorPosition(hOut, crCurr);
    return 0;
}
int main(int argc, char* argv[])
{
    int i;
    hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleScreenBufferInfo(hOut, &bInfo);

    for (i=0;i<100;i++)
    {
        ProgressBar("test", 0, i);
        Sleep(50);
    }

    return 0;
}

कहाँ bInfoपरिभाषित किया गया है?
टॉम ज़ातो -

3

PowerShell में राइट-प्रोग्रेस cmdlet है जो इन-कंसोल प्रोग्रेस बार बनाता है जिसे आप अपनी स्क्रिप्ट के रूप में अपडेट और संशोधित कर सकते हैं।


3

यहाँ आपके प्रश्न का उत्तर है ... (अजगर)

def disp_status(timelapse, timeout):
  if timelapse and timeout:
     percent = 100 * (float(timelapse)/float(timeout))
     sys.stdout.write("progress : ["+"*"*int(percent)+" "*(100-int(percent-1))+"]"+str(percent)+" %")
     sys.stdout.flush()
     stdout.write("\r  \r")

2

ग्रेग के उत्तर के अनुसरण के रूप में , यहां उनके फ़ंक्शन का एक विस्तारित संस्करण है जो आपको बहु-पंक्ति संदेशों को प्रदर्शित करने की अनुमति देता है; बस एक सूची या स्ट्रिंग का प्रदर्शन करें जिसे आप प्रदर्शित / ताज़ा करना चाहते हैं।

def status(msgs):
    assert isinstance(msgs, (list, tuple))

    sys.stdout.write(''.join(msg + '\n' for msg in msgs[:-1]) + msgs[-1] + ('\x1b[A' * (len(msgs) - 1)) + '\r')
    sys.stdout.flush()

नोट: मैंने केवल एक लिनक्स टर्मिनल का उपयोग करके इसका परीक्षण किया है, इसलिए आपका माइलेज विंडोज-आधारित सिस्टम पर भिन्न हो सकता है।


@naxa क्या ग्रेग का जवाब (उपरोक्त) आपके लिए काम करता है? यह सबसे अधिक संभावना है कि नए चरित्र के साथ एक समस्या है। '\ N' को '\ r \ n' से बदलने का प्रयास करें।
ब्लेक

ग्रेग का काम है, इसलिए एक लाइन पर यह काम करता है, लेकिन मैंने मल्टी-लाइन संदेश अपडेट करने की कोशिश की। :) मैंने आपकी स्क्रिप्ट में जगह ले ली \nहै \r\n, लेकिन फिर भी यह विंडोज़ पर काम नहीं कर पाया (क्या आप?)। मुझे ←[A←[Aकुछ संदेशों के बाद मिल रहा है , मुझे संदेह है कि '\x1b[A'अनुक्रम ऐसा नहीं करता है जो इसमें होना चाहिए cmd.exe
n611x007

1
@naxa '\ X1b [A' कर्सर अप के लिए एक ANSI एस्केप अनुक्रम है, जिसका उपयोग कर्सर को मेरे कोड में लाइनों के ब्लॉक की शुरुआत के लिए रीसेट करने के लिए किया जाता है। मैंने इस पर थोड़ा और गौर किया और पाया कि Win32 कंसोल ANSI एस्केप सीक्वेंस का बिल्कुल समर्थन नहीं करता है । आप विंडोज पर stdout को ANSI समर्थन जोड़ने के लिए यहां वर्णित समाधान को लपेटने के लिए मेरे फ़ंक्शन में एक if स्टेटमेंट जोड़ना चाह सकते हैं ।
ब्लेकर

0

यदि आपकी स्क्रिप्टिंग भाषा का उपयोग करके आप इसे प्राप्त करने के लिए "tput cup" कमांड का उपयोग कर सकते हैं ... PS यह एक लिनक्स / यूनिक्स चीज़ है जहाँ तक मैं जानता हूँ ...

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.