ฉันจะสะท้อนและส่งเอาต์พุตคอนโซลไปยังไฟล์ในสคริปต์ค้างคาวได้อย่างไร


140

ฉันมีสคริปต์ชุดงานที่ดำเนินการงานและส่งผลลัพธ์ไปยังไฟล์ข้อความ มีวิธีให้เอาต์พุตแสดงบนหน้าต่างคอนโซลด้วยหรือไม่?

ตัวอย่างเช่น:

c:\Windows>dir > windows-dir.txt

มีวิธีการdirแสดงผลในหน้าต่างคอนโซลและใส่ลงในไฟล์ข้อความหรือไม่?


นี่คือคำอธิบายเกี่ยวกับการเปลี่ยนเส้นทางที่คุณสามารถทำได้และตัวอย่างบางส่วน <br> หวังว่าจะช่วยได้ :)
emoSTN


โปรดทราบว่า @Vadzim คำถามที่ถามเมื่อวันที่ 2 กุมภาพันธ์ 2552 เวลา 16:38 น. ไม่สามารถถือว่าซ้ำกับคำถามที่ถามเกือบสามเดือนต่อมาในวันที่ 28 เมษายน 2552 เวลา 06:32 น.
Compo

คำตอบ:


219

ไม่คุณไม่สามารถเปลี่ยนเส้นทางได้อย่างแท้จริง
แต่ด้วยเทคนิคบางอย่าง (เช่นtee.bat ) คุณสามารถทำได้

ฉันพยายามอธิบายการเปลี่ยนเส้นทางสักหน่อย

คุณเปลี่ยนเส้นทางหนึ่งในสิบสตรีมด้วย> fileหรือ<file
ซึ่งไม่สำคัญหากการเปลี่ยนเส้นทางอยู่ก่อนหรือหลังคำสั่งดังนั้นทั้งสองบรรทัดจึงใกล้เคียงกัน

dir > file.txt
> file.txt dir

การเปลี่ยนเส้นทางในตัวอย่างนี้เป็นเพียงทางลัดสำหรับ1>ซึ่งหมายความว่าสตรีม 1 (STDOUT) จะถูกเปลี่ยนเส้นทาง
ดังนั้นคุณสามารถเปลี่ยนเส้นทางสตรีมใดก็ได้โดยใส่หมายเลขไว้ล่วงหน้าเช่น2> err.txtและยังได้รับอนุญาตให้เปลี่ยนเส้นทางสตรีมหลายรายการในบรรทัดเดียว

dir 1> files.txt 2> err.txt 3> nothing.txt

ในตัวอย่างนี้ "เอาต์พุตมาตรฐาน" จะเข้าสู่ files.txt ข้อผิดพลาดทั้งหมดจะอยู่ใน err.txt และ stream3 จะกลายเป็น nothing.txt (DIR ไม่ใช้สตรีม 3)
Stream0 คือ STDIN
Stream1 คือ STDOUT
Stream2 คือ STDERR
Stream3-9 ไม่ได้ใช้

แต่จะเกิดอะไรขึ้นหากคุณพยายามเปลี่ยนเส้นทางสตรีมเดียวกันหลาย ๆ ครั้ง

dir > files.txt > two.txt

"มีได้เพียงหนึ่งเดียว" และสุดท้ายเสมอ!
มันจึงเท่ากับdir> two.txt

โอเคมีความเป็นไปได้พิเศษอย่างหนึ่งคือเปลี่ยนเส้นทางสตรีมไปยังสตรีมอื่น

dir 1>files.txt 2>&1 

2> & 1การเปลี่ยนเส้นทางไป stream2 stream1 และ1> files.txtเปลี่ยนเส้นทางทั้งหมดเพื่อfiles.txt
คำสั่งมีความสำคัญที่นี่!

dir ... 1>nul 2>&1
dir ... 2>&1 1>nul

แตกต่าง. บรรทัดแรกเปลี่ยนเส้นทางทั้งหมด (STDOUT และ STDERR) ไปยัง NUL
แต่บรรทัดที่สองเปลี่ยนเส้นทาง STDOUT เป็น NUL และ STDERR ไปยัง STDOUT "ว่าง"

สรุปได้ชัดเจนว่าเหตุใดตัวอย่างของOtávioDécioและ andynormancx จึงไม่สามารถใช้งานได้

command > file >&1
dir > file.txt >&2

ทั้งสองพยายามเปลี่ยนเส้นทาง stream1 สองครั้ง แต่ "มีได้เพียงครั้งเดียว" และเป็นครั้งสุดท้ายเสมอ
คุณจะได้รับ

command 1>&1
dir 1>&2

และในตัวอย่างแรกไม่อนุญาตให้เปลี่ยนเส้นทาง stream1 ไปยัง stream1 (และไม่มีประโยชน์มากนัก)

หวังว่าจะช่วยได้


24
ดังนั้นจึงเป็นไปไม่ได้ที่จะใช้ windows shell
fantastory

7
@fantastory เป็นไปได้ดูโซลูชันที่ยอดเยี่ยมของ dbenham Windows batch: คำสั่ง 'tee'
jeb

100
ฉันไม่อยากเชื่อเลยว่าฉันเพิ่งอ่านโพสต์ทั้งหมดนี้เพื่อดูว่าทั้งหมดสามารถสรุปได้ว่า "ไม่"
Charles McKelvey

1
แล้วกลไกที่สอง "จัดการการทำสำเนา" ล่ะ? ผมทดลองกับ3<&2(หมายเหตุ LT แทน GT) 3>errors.txtและจากนั้น แต่สิ่งนี้จบลงอย่างไม่ดี - เอาต์พุต stderr ที่ตามมาทั้งหมดถูกจับไปที่errors.txt(นั่นคือ - จากคำสั่งอื่นด้วย!)
Tomasz Gandor

1
@CharlesMcKelvey (และผู้โหวตทั้งหมด) คุณจะยอมรับคำตอบที่ระบุว่า "ไม่" หรือไม่ หรือคุณต้องการคำอธิบายบางอย่าง?
Rodrigo.A92

33

เพียงใช้คำสั่ง UNIX tee เวอร์ชัน Windows (พบจากhttp://unxutils.sourceforge.net ) ด้วยวิธีนี้:

mycommand > tee outpu_file.txt

หากคุณต้องการเอาต์พุต STDERR ด้วยให้ใช้สิ่งต่อไปนี้ รวมการส่งออก STDERR ลง STDOUT (กระแสหลัก)
2>&1

mycommand 2>&1 | tee output_file.txt

3
PowerShell Tee-วัตถุมีฟังก์ชันการทำงานที่คล้ายกัน รับกระบวนการ | Tee-Object -file c: \ scripts \ test.txt
Kevin Obee

ฉันลองสิ่งนี้ทั้งใน powershell และเปลือกปกติ 1>tee a.txtจะเปลี่ยนเส้นทาง stdout ไปยังไฟล์ที่มีชื่อteeแทนที่จะเรียกteeคำสั่ง มีใครยืนยันได้ไหมว่าคำตอบนี้เหมาะกับพวกเขา
mafu

@mafu ฉันสามารถยืนยันสิ่งนี้ได้
Cerno

@mafu คำตอบข้างต้นเป็นเรื่องเล็กน้อย คุณต้องใช้ท่อ "|" แทน ">" ในตัวอย่างด้านบน น่าแปลกที่ลำดับของเอาต์พุต STDOUT และ STDERR ผสมกันในบรรทัดคำสั่งในกรณีนั้น ตัวอย่างด้านล่างทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน
Cerno

นอกจากนี้การดาวน์โหลด sourceforge ก็เสียสำหรับฉัน ฉันพบโฮสต์ทางเลือกที่นี่: wzw.tum.de/public-html/syring/win32/UnxUtilsDist.html (University of Munich)
Cerno

9

หากคุณไม่ต้องการผลลัพธ์แบบเรียลไทม์ (เช่นขณะที่โปรแกรมกำลังเขียน) คุณสามารถเพิ่มได้

type windows-dir.txt

หลังจากบรรทัดนั้น


หรือในบรรทัดเดียวกัน dir > windows-dir.txt & type windows-dir.txt(มีประโยชน์ที่พร้อมท์): ( echo %date% <NL> echo %username% <NL> echo %time% <NL> pause>CON )>test.txt & type test.txtนี้ยังใช้กับบล็อก: อย่างไรก็ตามหากต้องการเอาต์พุตแบบเรียลไทม์คุณสามารถใช้เช่นพอร์ต windows ของเครื่องมือทีสำหรับสิ่งนั้น ...
mousio

7

วิธีแก้ปัญหาที่ใช้ได้ผลสำหรับฉันคือ: dir> a.txt | ประเภท a.txt


2
สิ่งนี้ใช้ได้กับคำสั่งที่มีเอาต์พุตต่ำ ด้วยคำสั่งเอาต์พุตขนาดใหญ่จะไม่ทำงานเนื่องจากแสดงเฉพาะบัฟเฟอร์แรก เขาขอเอาต์พุตแบบเรียลไทม์ในขณะที่บันทึกผลลัพธ์ลงในล็อกไฟล์
NetVicious

มันจะเป็นปัญหาถ้าคุณใช้ >> แทน>
Nime Cloud

6

ใช่มีวิธีแสดงเอาต์พุตคำสั่งเดียวบนคอนโซล (หน้าจอ) และในไฟล์ โดยใช้ตัวอย่างของคุณใช้ ...

@ECHO OFF
FOR /F "tokens=*" %%I IN ('DIR') DO ECHO %%I & ECHO %%I>>windows-dir.txt

คำอธิบายโดยละเอียด:

FORคำสั่งแยกวิเคราะห์ผลลัพธ์ของคำสั่งหรือข้อความลงในตัวแปรซึ่งสามารถอ้างอิงหลายครั้ง

สำหรับคำสั่งเช่นDIR /Bใส่เครื่องหมายคำพูดเดี่ยวตามที่แสดงในตัวอย่างด้านล่าง แทนที่DIR /Bข้อความด้วยคำสั่งที่คุณต้องการ

FOR /F "tokens=*" %%I IN ('DIR /B') DO ECHO %%I & ECHO %%I>>FILE.TXT

สำหรับการแสดงข้อความให้ใส่ข้อความในเครื่องหมายคำพูดคู่ดังที่แสดงในตัวอย่างด้านล่าง

FOR /F "tokens=*" %%I IN ("Find this text on console (screen) and in file") DO ECHO %%I & ECHO %%I>>FILE.TXT

... และด้วยการพันเส้น ...

FOR /F "tokens=*" %%I IN ("Find this text on console (screen) and in file") DO (
  ECHO %%I & ECHO %%I>>FILE.TXT
)

ถ้าคุณมีครั้งเมื่อคุณต้องการส่งออกเฉพาะบนคอนโซล (หน้าจอ) และครั้งอื่น ๆ ที่ส่งไปยังไฟล์และครั้งอื่น ๆ ที่ส่งทั้งระบุ "DO" %TOECHOWHERE%ประโยคของใช้สำหรับวงตัวแปรตามที่แสดงด้านล่างด้วย

@ECHO OFF
FOR %%I IN (TRUE FALSE) DO (
  FOR %%J IN (TRUE FALSE) DO (
    SET TOSCREEN=%%I & SET TOFILE=%%J & CALL :Runit)
)
GOTO :Finish

:Runit
  REM Both TOSCREEN and TOFILE get assigned a trailing space in the FOR loops
  REM above when the FOR loops are evaluating the first item in the list,
  REM "TRUE".  So, the first value of TOSCREEN is "TRUE " (with a trailing
  REM space), the second value is "FALSE" (no trailing or leading space).
  REM Adding the ": =" text after "TOSCREEN" tells the command processor to
  REM remove all spaces from the value in the "TOSCREEN" variable.
  IF "%TOSCREEN: =%"=="TRUE" (
      IF "%TOFILE: =%"=="TRUE" (
          SET TEXT=On screen, and in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I & ECHO %%I>>FILE.TXT"
        ) ELSE (
          SET TEXT=On screen, not in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I"
      )
    ) ELSE (
      IF "%TOFILE: =%"=="TRUE" (
          SET TEXT=Not on screen, but in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I>>FILE.txt"
        ) ELSE (
          SET TEXT=Not on screen, nor in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I>NUL"
      )
  )
  FOR /F "tokens=*" %%I IN ("%TEXT%") DO %TOECHOWHERE:~1,-1%
GOTO :eof

:Finish
  ECHO Finished [this text to console (screen) only].
  PAUSE

คุณควรใช้delims=แทน
scriptmastere02

3
command > file >&1

เร็วกว่าเมื่อคุณไม่เขียนข้อมูลออกไปที่หน้าจอเนื่องจากคุณไม่ได้เติมบัฟเฟอร์ด้วยอึ แต่ให้คุณทำงานเป็นกลุ่ม หากคุณกำลังดีบักฉันจะไม่ใช้ไวยากรณ์ไฟล์>
Random Developer

@andynormancx ใช่ลืมพิมพ์แทนที่จะตัดและวางจาก CMD
Random Developer

ฉันไม่สามารถทำให้ไวยากรณ์ทำงานภายใต้พรอมต์คำสั่งของ windows และใช้คำสั่ง type แทน
JamesEggers

& 2 ใช้งานได้ แต่ตอนนี้ไฟล์ไม่ได้ถูกสร้างขึ้นเมื่อฉันทดสอบ
JamesEggers

5
ถ้าฉันทำ "dir> file.txt> & 2" file.txt จะไม่ถูกสร้างขึ้น เอาต์พุตของไดเร็กทอรีกำลังถูกสะท้อนในคอนโซล แต่ไฟล์ไม่ได้ถูกสร้างขึ้น ไฟล์ถูกสร้างขึ้นเมื่อไม่มี "> & 2"
JamesEggers

2

หากคุณต้องการต่อท้ายแทนการแทนที่ไฟล์ผลลัพธ์คุณอาจต้องการใช้

dir 1>> files.txt 2>> err.txt

หรือ

dir 1>> files.txt 2>>&1

2

ตัวเลือกของฉันคือ:

สร้างรูทีนย่อยที่รับข้อความและทำให้กระบวนการส่งไปยังคอนโซลและล็อกไฟล์โดยอัตโนมัติ

setlocal
set logfile=logfile.log

call :screenandlog "%DATE% %TIME% This message goes to the screen and to the log"    

goto :eof

:screenandlog
set message=%~1
echo %message% & echo %message% >> %logfile%
exit /b

หากคุณเพิ่มตัวแปรลงในข้อความอย่าลืมลบเครื่องหมายคำพูดในนั้นออกก่อนที่จะส่งไปยังรูทีนย่อยมิฉะนั้นจะทำให้แบตช์ของคุณเสียหายได้ แน่นอนว่าสิ่งนี้ใช้ได้กับการสะท้อนเท่านั้น


ว้าวใช่! ชอบเรื่องนี้มาก !! ฉันทำการเปลี่ยนแปลงสามครั้ง แต่หวังว่าคุณจะชอบ 1)ฉันใช้setlocal enabledelayedexpansionแทนแค่setlocal 2)ฉันใช้การขยายล่าช้าสำหรับตัวแปร logfile ดังนั้น>> !logfile!แทนที่จะใช้>> %logfile%ภายในรูทีนย่อย วิธีนี้จะทำงานเมื่อถูกเรียกจากภายในบล็อกรหัส (เช่นภายในคำสั่ง if) 3)ฉันลบบรรทัด "set message" ออกเพราะไม่จำเป็นต้องใช้ตัวแปรเพิ่มเติม เรามีมันอยู่แล้ว$~1ดังนั้นฉันจึงมีecho $~1ทั้งคำสั่ง echo
เนท

2

ฉันสร้างคอนโซล C # ง่ายๆซึ่งสามารถจัดการเอาต์พุตแบบเรียลไทม์ไปยังทั้งหน้าจอ cmd และบันทึก

class Tee
{
    static int Main(string[] args)
    {
        try
        {
            string logFilePath = Path.GetFullPath(args[0]);

            using (StreamWriter writer = new StreamWriter(logFilePath, true))
            {
                for (int value; (value = Console.In.Read()) != -1;)
                {
                    var word = Char.ConvertFromUtf32(value);
                    Console.Write(word);
                    writer.Write(word);
                }
            }
        }
        catch (Exception)
        {
            return 1;
        }
        return 0;
    }
}

การใช้งานไฟล์แบตช์จะเหมือนกับวิธีที่คุณใช้ Unix tee

foo | tee xxx.log

และนี่คือที่เก็บซึ่งรวมถึง Tee.exe ในกรณีที่คุณไม่มีเครื่องมือในการรวบรวม https://github.com/iamshiao/Tee


1

ฉันชอบคำตอบของ atn แต่มันก็ไม่ได้เป็นเรื่องเล็กน้อยสำหรับฉันที่จะดาวน์โหลดเป็นwinteeซึ่งเป็นโอเพ่นซอร์สและให้ฟังก์ชันทีเท่านั้น (มีประโยชน์หากคุณต้องการเพียงแค่ทีและไม่ใช่ยูทิลิตี้ยูนิกซ์ทั้งชุด) ฉันได้เรียนรู้เกี่ยวกับสิ่งนี้จากคำตอบของ davor เกี่ยวกับการแสดงเอาต์พุตพรอมต์คำสั่งของ Windows และเปลี่ยนเส้นทางไปยังไฟล์ซึ่งคุณจะพบการอ้างอิงถึงยูทิลิตี้ unix ด้วย


0

โซลูชันที่จัดทำโดย "Tomas R" ทำงานได้อย่างสมบูรณ์แบบสำหรับคำถามของ OP และสามารถใช้ได้โดยกำเนิด

ลอง: chkdsk c:> output.txt | พิมพ์ output.txt

ผลลัพธ์เป็นของคำสั่งนี้เกี่ยวข้องกับเปอร์เซ็นต์ความสมบูรณ์ที่ได้รับเอาต์พุตแบบต่อเนื่องไปยังไฟล์ดังนั้นมันจะดูยุ่งเล็กน้อย (กล่าวคือข้อความจะถูกต่อท้ายเมื่อดำเนินการ) สิ่งนี้ไม่เกิดขึ้นกับบิตที่ได้รับเอาต์พุตไปยัง STDOUT (หน้าจอ) มันจะเป็นอย่างไรถ้าคุณทำคำสั่งเดิมโดยไม่เปลี่ยนเส้นทาง


-3

ฉันคิดว่าคุณต้องการบางอย่างตามแนวนี้:

echo Your Msg> YourTxtFile.txt

หรือหากต้องการขึ้นบรรทัดใหม่:

echo Your Msg>> YourTxtFile.txt

คำสั่งเหล่านี้เหมาะสำหรับบันทึก

หมายเหตุ: บางครั้งอาจเกิดความผิดพลาดและแทนที่ไฟล์ข้อความทั้งหมดในคอมพิวเตอร์ของฉัน

หมายเหตุอื่น: หากไม่มีไฟล์อยู่ไฟล์จะสร้างไฟล์


1
ไม่ OP ต้องการให้เอาต์พุตเป็นไฟล์และบนหน้าจอ ของคุณเพียงแค่เขียนลงในไฟล์ (และ>ถูกออกแบบมาเพื่อแทนที่การใช้ไฟล์. >>เพื่อผนวก )
สเตฟาน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.