ปราบปรามเอาต์พุตบรรทัดคำสั่ง


118

ฉันมีไฟล์แบตช์ง่ายๆดังนี้:

ปิดเสียงสะท้อน

taskkill / im "test.exe" / f> nul

หยุด

หาก "test.exe" ไม่ทำงานฉันจะได้รับข้อความนี้:

ข้อผิดพลาด: ไม่พบกระบวนการ "test.exe"

เหตุใดข้อความแสดงข้อผิดพลาดนี้จึงปรากฏขึ้นแม้ว่าฉันจะเปลี่ยนเส้นทางเอาต์พุตไปยัง NUL แล้วก็ตาม

ฉันจะระงับผลลัพธ์นั้นได้อย่างไร

คำตอบ:


212

เพราะข้อความผิดพลาดที่มักจะไปไม่ได้stderrstdout

เปลี่ยนคำเรียกร้องเป็น:

taskkill /im "test.exe" /f >nul 2>&1

และทั้งหมดจะดีขึ้น

ใช้งานได้เนื่องจากstdoutเป็น file descriptor 1 และstderrเป็น file descriptor 2 ตามแบบแผน (0 คือstdinโดยบังเอิญ) 2>&1สำเนาไฟล์เอาต์พุต descriptor 2 จากค่าใหม่ของ 1 ซึ่งเพิ่งเปลี่ยนเส้นทางไปยังอุปกรณ์ null

ไวยากรณ์นี้ (แบบหลวม ๆ ) ยืมมาจาก Unix เชลล์จำนวนมาก แต่คุณต้องระวังเนื่องจากมีความแตกต่างเล็กน้อยระหว่างไวยากรณ์ของเชลล์และ CMD.EXE

อัปเดต:ฉันรู้ว่า OP เข้าใจลักษณะพิเศษของ "ไฟล์" ที่ชื่อNULฉันเขียนถึงที่นี่ แต่ผู้แสดงความคิดเห็นไม่ได้แจ้งรายละเอียดเพิ่มเติมเล็กน้อยเกี่ยวกับแง่มุมนั้นให้ฉันฟัง

เมื่อย้อนกลับไปที่ MSDOS รุ่นแรกสุดชื่อไฟล์บางไฟล์จะถูกยึดไว้ล่วงหน้าโดยเคอร์เนลระบบไฟล์และใช้เพื่ออ้างถึงอุปกรณ์ รายการแรกของชื่อเหล่านั้นรวมNUL, PRN, CON, AUXและผ่านCOM1 เป็นอุปกรณ์ว่าง สามารถเปิดได้ตลอดเวลาสำหรับการอ่านหรือการเขียนสามารถเขียนจำนวนเท่าใดก็ได้และอ่านได้เสมอ แต่ไม่ส่งคืนข้อมูล อื่น ๆ รวมถึงพอร์ตเครื่องพิมพ์ขนานคอนโซลและพอร์ตอนุกรมสูงสุดสี่พอร์ต ตั้งแต่ MSDOS 5 มีชื่อที่สงวนไว้อีกหลายชื่อ แต่อนุสัญญาพื้นฐานได้รับการยอมรับเป็นอย่างดีCOM4NUL

เมื่อ Windows ถูกสร้างขึ้นมันเริ่มต้นชีวิตด้วยเลเยอร์การสลับแอปพลิเคชันที่ค่อนข้างบางที่ด้านบนของเคอร์เนล MSDOS ดังนั้นจึงมีข้อ จำกัด ชื่อไฟล์เหมือนกัน เมื่อ Windows NT ถูกสร้างขึ้นเป็นระบบปฏิบัติการที่แท้จริงในสิทธิ์ของตัวเองชื่อที่เหมือนNULและCOM1ถูกสันนิษฐานอย่างกว้างขวางเกินไปว่าจะทำงานเพื่ออนุญาตให้ลบออกได้ อย่างไรก็ตามความคิดที่ว่าอุปกรณ์ใหม่มักจะได้รับชื่อที่จะบล็อกผู้ใช้ในอนาคตของชื่อเหล่านั้นสำหรับไฟล์จริงนั้นไม่สมเหตุสมผล

Windows NT และทุกเวอร์ชันที่ตามมา (2K, XP, 7 และตอนนี้ 8) ทั้งหมดตามมาใช้Namespace NT ที่ซับซ้อนมากขึ้นจากรหัสเคอร์เนลและเพื่อสร้างรหัสพื้นที่ผู้ใช้อย่างระมัดระวังและไม่พกพาได้สูง ในพื้นที่ชื่อนั้นไดรเวอร์อุปกรณ์จะมองเห็นได้ผ่าน\Deviceโฟลเดอร์ เพื่อรองรับความเข้ากันได้แบบย้อนหลังที่จำเป็นมีกลไกพิเศษโดยใช้\DosDevicesโฟลเดอร์ที่ใช้รายชื่อไฟล์ที่สงวนไว้ในโฟลเดอร์ระบบไฟล์ใด ๆ รหัสผู้ใช้สามารถเรียกดูพื้นที่ชื่อภายในนี้โดยใช้ชั้น API ที่อยู่ด้านล่าง Win32 API ปกติ เครื่องมือที่ดีในการสำรวจเนมสเปซเคอร์เนลคือWinObjจากกลุ่ม SysInternals ที่ Microsoft

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


5
ขอบคุณสำหรับคำตอบและที่สำคัญที่สุดสำหรับคำอธิบาย
JosephStyons

คำแนะนำ: taskkill /im "test.exe" /f >%temp%\nul 2>&1 & del %temp%\nul. สิ่งนี้จะป้องกันไม่ให้ไฟล์ว่างเปล่าถูกวางลงในไดเร็กทอรีท้องถิ่น
Samy Bencherif

11
@SamyBencherif NULเป็นชื่อไฟล์ที่สงวนไว้และแมปกับอุปกรณ์ NUL คุณไม่สามารถสร้างไฟล์จริงที่ตั้งชื่อNULในไดเร็กทอรีใด ๆ
RBerteig

7

ใช้สคริปต์นี้แทน:

@taskkill/f /im test.exe >nul 2>&1
@pause

สิ่งที่2>&1ส่วนนี้ทำจริงคือมันเปลี่ยนเส้นทางstderrเอาต์พุตไปที่stdoutออกไปฉันจะอธิบายให้ดีขึ้นด้านล่าง:

@ taskkill / f / im test.exe> ​​nul 2> & 1

ฆ่างาน "test.exe" เปลี่ยนเส้นทางไปยังstderr stdoutจากนั้นเปลี่ยนเส้นทางstdoutไปที่nulไปยัง

@หยุด

แสดงข้อความหยุดชั่วคราว Press any key to continue . . . จนกว่าจะมีคนกดแป้น

หมายเหตุ: @สัญลักษณ์นี้ซ่อนพร้อมต์สำหรับแต่ละคำสั่ง คุณสามารถประหยัดได้ถึง 8 ไบต์ด้วยวิธีนี้

รุ่นที่สั้นที่สุดของสคริปต์ของคุณอาจจะ: ตัวละครที่ถูกนำมาใช้สำหรับการเปลี่ยนเส้นทางเป็นครั้งแรกและสำหรับการแยกคำสั่งเป็นครั้งที่สอง ตัวละครไม่จำเป็นต้องเป็นครั้งที่สองในสาย รหัสนี้มีขนาดเพียง 40 ไบต์แม้ว่ารหัสที่คุณโพสต์จะมีขนาด 49 ไบต์ก็ตาม! จริง ๆ แล้วฉันบันทึก 9 ไบต์ สำหรับรหัสที่สะอาดกว่าดูด้านบน
@taskkill/f /im test.exe >nul 2>&1&pause
&
@


ใช่ฉันรู้ว่าครึ่งหนึ่งของโพสต์คือวิธีย่อโค้ดของคุณ
EKons

3

mysqldump ใช้ไม่ได้กับ: > nul 2> & 1
แทนที่จะใช้: 2> nul
สิ่งนี้จะระงับข้อความ stderr: "คำเตือน: การใช้รหัสผ่านบนอินเทอร์เฟซบรรทัดคำสั่งอาจไม่ปลอดภัย"


0

คุณสามารถทำได้เช่นกัน:

tasklist | find /I "test.exe" > nul && taskkill /f /im test.exe > nul

แม้ว่าบริบทของคำถามจะเป็นสคริปต์แบตช์ แต่ฉันพบว่าใน PowerShell ไวยากรณ์ข้างต้นล้มเหลวด้วย " out-file: FileStream ถูกขอให้เปิดอุปกรณ์ที่ไม่ใช่ไฟล์สำหรับการสนับสนุนอุปกรณ์เช่น 'com1:' หรือ 'lpt1: 'เรียก CreateFile จากนั้นใช้ตัวสร้าง FileStream ที่ใช้ตัวจัดการ OS เป็น IntPtr "วิธีแก้ปัญหาคือแทนที่> nulด้วย>$null.
ฝาย
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.