كيف يمكنني تشغيل تطبيق لسطر الأوامر في موجه أوامر Windows وعرض الإخراج وإعادة توجيهه إلى ملف في نفس الوقت؟
على سبيل المثال ، إذا كنت سأقوم بتشغيل الأمر dir > test.txt
، فسيؤدي ذلك إلى إعادة توجيه الإخراج إلى ملف يسمى test.txt
دون عرض النتائج.
كيف يمكنني كتابة أمر لعرض الإخراج و إعادة توجيه الإخراج إلى ملف في موجه أوامر Windows ، على غرار الأمر tee
في يونكس؟
للتوسع في إجابة دافور ، يمكنك استخدام PowerShell مثل هذا:
powershell "dir | tee test.txt"
إذا كنت تحاول إعادة توجيه إخراج exe في الدليل الحالي ، فأنت بحاجة إلى استخدام .\
في اسم الملف ، على سبيل المثال:
powershell ".\something.exe | tee test.txt"
تمكنت من العثور على حل/حل بديل لإعادة توجيه الإخراج إلى ملف ثم إلى وحدة التحكم:
dir > a.txt | type a.txt
حيث dir هو الأمر الذي يحتاج إلى إعادة توجيه الإخراج ، a.txt ملف حيث يتم تخزين الإخراج.
يوجد منفذ Win32 للأمر Unix tee
، يقوم بذلك بالضبط. انظر http://unxutils.sourceforge.net/ أو http://getgnuwin32.sourceforge.net/
تحقق من ذلك: wintee
لا حاجة ل cygwin.
لقد صادفت وأبلغ عن بعض المشكلات.
كما يمكنك التحقق من unxutils لأنه يحتوي على نقطة الإنطلاق (وليس هناك حاجة إلى cygwin) ، ولكن حذار أن إخراج EOL هي مثل UNIX هنا.
أخيرًا وليس آخرًا ، إذا كان لديك PowerShell ، فيمكنك تجربة Tee-Object. اكتب get-help tee-object
في وحدة التحكم PowerShell لمزيد من المعلومات.
@ tori3852
لقد وجدت ذلك
dir > a.txt | type a.txt
لم تنجح (الأسطر القليلة الأولى من قائمة dir فقط - تشك في وجود نوع من عملية التهيئة والجزء الثاني ، تم إنهاء الأمر "type" قبل أن تكتمل القائمة الرهيبة؟) ، لذا بدلاً من ذلك استخدمت:
dir > z.txt && type z.txt
التي فعلت - الأوامر التسلسلية ، واحد يكمل قبل أن يبدأ الثاني.
تطبيق وحدة تحكم C # بسيط سيفعل الخدعة:
using System;
using System.Collections.Generic;
using System.IO;
namespace CopyToFiles
{
class Program
{
static void Main(string[] args)
{
var buffer = new char[100];
var outputs = new List<TextWriter>();
foreach (var file in args)
outputs.Add(new StreamWriter(file));
outputs.Add(Console.Out);
int bytesRead;
do
{
bytesRead = Console.In.ReadBlock(buffer, 0, buffer.Length);
outputs.ForEach(o => o.Write(buffer, 0, bytesRead));
} while (bytesRead == buffer.Length);
outputs.ForEach(o => o.Close());
}
}
}
لاستخدام هذا الأمر ، عليك فقط توجيه الأمر source إلى البرنامج وتوفير مسار أي ملفات تريد تكرار الإخراج إليها. فمثلا:
dir | CopyToFiles files1.txt files2.txt
سيتم عرض نتائج dir وكذلك تخزين النتائج في كل من files1.txt و files2.txt.
لاحظ أنه لا يوجد الكثير (أي شيء!) في طريق معالجة الأخطاء أعلاه ، وقد لا يكون دعم ملفات متعددة مطلوبًا بالفعل.
للأسف لا يوجد شيء من هذا القبيل.
تحتوي تطبيقات وحدة التحكم في Windows فقط على مؤشر إخراج واحد. (حسنًا ، هناك نوعان STDOUT
، STDERR
لكن لا يهم هنا) >
يعيد توجيه الإخراج المكتوب عادةً إلى مقبض وحدة التحكم إلى مقبض ملف.
إذا كنت ترغب في الحصول على نوع من الإرسال المتعدد ، فيجب عليك استخدام تطبيق خارجي يمكنك تحويل الإخراج إليه. ثم يمكن لهذا التطبيق الكتابة إلى ملف وإلى وحدة التحكم مرة أخرى.
هذا يعمل ، رغم أنه قبيح بعض الشيء:
dir >_ && type _ && type _ > a.txt
إنها أكثر مرونة قليلاً من بعض الحلول الأخرى ، حيث إنها تعمل بيانًا تلو الآخر حتى تتمكن من استخدامه للإلحاق أيضًا. أستخدم هذا قليلاً في ملفات الدُفعات لتسجيل الرسائل وعرضها:
ECHO Print line to screen and log to file. >_ && type _ && type _ >> logfile.txt
نعم ، يمكنك فقط تكرار عبارة ECHO (مرة واحدة للشاشة والمرة الثانية إعادة التوجيه إلى ملف السجل) ، لكن يبدو الأمر سيئًا ويعد مشكلة صيانة قليلاً. على الأقل بهذه الطريقة ، لا يتعين عليك إجراء تغييرات على الرسائل في مكانين.
لاحظ أن _ مجرد اسم ملف قصير ، لذلك ستحتاج إلى التأكد من حذفه في نهاية ملف الدُفعات الخاص بك (إذا كنت تستخدم ملف دفعي).
mtee هي أداة صغيرة والتي تعمل بشكل جيد للغاية لهذا الغرض. إنه مجاني ، والمصدر مفتوح ، ويعمل فقط.
يمكنك العثور عليه في http://www.commandline.co.uk .
يستخدم في ملف دفعي لعرض الإخراج وإنشاء ملف سجل في وقت واحد ، يبدو بناء الجملة كما يلي:
someprocess | mtee /+ mylogfile.txt
حيث/+ يعني إلحاق الإخراج.
هذا يفترض أنك قمت بنسخ mtee في مجلد موجود في المسار ، بالطبع.
وأنا أتفق مع برايان راسموسين ، وميناء unxutils هو أسهل طريقة للقيام بذلك. في ملفات الدُفعات قسم صفحته صفحات البرمجة النصية يوفر Rob van der Woude ثروة من المعلومات عن استخدام أوامر MS-DOS و CMD. اعتقدت أنه ربما يكون لديه حل أصلي لمشكلتك ، وبعد البحث من هناك ، وجدت TEE.BAT ، والذي يبدو أنه تطبيق لغة دفعية من MS-DOS تمامًا. إنه ملف دفعي ذو مظهر معقد إلى حد كبير ولا يزال ميلي هو استخدام منفذ unxutils.
أرغب في التوسع قليلاً في برنامج Saxon Druce إجابة ممتازة .
كما هو مذكور ، يمكنك إعادة توجيه إخراج الملف التنفيذي في الدليل الحالي مثل:
powershell ".\something.exe | tee test.txt"
ومع ذلك ، يسجل هذا فقط stdout
إلى test.txt
. إنه لا يسجل أيضًا stderr
.
الحل الواضح هو استخدام شيء مثل هذا:
powershell ".\something.exe 2>&1 | tee test.txt"
ومع ذلك ، لن يعمل هذا مع جميع something.exe
s. بعض something.exe
s ستفسر 2>&1
على أنها وسيطة وتفشل. الحل الصحيح هو بدلاً من ذلك أن يكون لديك علامة اقتباس أحادية حول رمز something.exe
فقط ، وهي مفاتيح وسيطات ، مثل ذلك:
powershell ".\something.exe --switch1 --switch2 … arg1 arg2 …" 2>&1 | tee test.txt
إذا كان لديك cygwin في مسار بيئة Windows ، فيمكنك استخدام:
dir > a.txt | tail -f a.txt
dir 1>a.txt 2>&1 | type a.txt
هذا سيساعد على إعادة توجيه كل من STDOUT و STDERR
كنت أبحث أيضًا عن نفس الحل ، وبعد قليل من المحاولة ، تمكنت من تحقيق ذلك بنجاح في Command Prompt. إليكم الحل:
@Echo off
for /f "Delims=" %%a IN (xyz.bat) do (
%%a > _ && type _ && type _ >> log.txt
)
@Echo on
حتى أنه يلتقط أي أمر PAUSE كذلك.
إرسال الإخراج إلى وحدة التحكم ، إلحاق سجل وحدة التحكم ، وحذف الإخراج من الأمر الحالي
dir >> usb-create.1 && type usb-create.1 >> usb-create.log | type usb-create.1 && del usb-create.1
شيء من هذا القبيل يجب أن تفعل ما تحتاجه؟
%DATE%_%TIME% > c:\a.txt & type c:\a.txt
ipconfig >> c:\a.txt & type c:\a.txt
ping localhost >> c:\a.txt & type c:\a.txt
pause
فيما يلي نموذج لما استخدمته استنادًا إلى أحد الإجابات الأخرى
@echo off
REM SOME CODE
set __ERROR_LOG=c:\errors.txt
REM set __IPADDRESS=x.x.x.x
REM Test a variable
if not defined __IPADDRESS (
REM Call function with some data and terminate
call :TEE %DATE%,%TIME%,IP ADDRESS IS NOT DEFINED
goto :EOF
)
REM If test happens to be successful, TEE out a message and end script.
call :TEE Script Ended Successful
goto :EOF
REM THE TEE FUNCTION
:TEE
for /f "tokens=*" %%Z in ("%*") do (
> CON ECHO.%%Z
>> "%__ERROR_LOG%" ECHO.%%Z
goto :EOF
)
أعلم أن هذا موضوع قديم جدًا ، لكن في الإجابات السابقة ، لا يوجد تنفيذ كامل لوقت حقيقي تم كتابته في Batch. حالي أدناه هو برنامج نصي مختلط Batch-JScript يستخدم قسم JScript فقط للحصول على الإخراج من الأمر piped ، ولكن تتم معالجة البيانات في قسم Batch. تتمتع هذه الطريقة بميزة أن أي مبرمج دفعي قد يعدل هذا البرنامج ليناسب احتياجات معينة. يقوم هذا البرنامج أيضًا بمعالجة إخراج أمر CLS الذي تم إنتاجه بواسطة ملفات دفعية أخرى بشكل صحيح ، أي أنه يمسح الشاشة عند اكتشاف إخراج أمر CLS.
@if (@CodeSection == @Batch) @then
@echo off
setlocal EnableDelayedExpansion
rem APATee.bat: Asynchronous (real time) Tee program, Batch-JScript hybrid version
rem Antonio Perez Ayala
rem The advantage of this program is that the data management is written in Batch code,
rem so any Batch programmer may modify it to fit their own needs.
rem As an example of this feature, CLS command is correctly managed
if "%~1" equ "" (
echo Duplicate the Stdout output of a command in the screen and a disk file
echo/
echo anyCommand ^| APATee teeFile.txt [/A]
echo/
echo If /A switch is given, anyCommand output is *appended* to teeFile.txt
goto :EOF
)
if "%2" equ ":TeeProcess" goto TeeProcess
rem Get the output of CLS command
for /F %%a in ('cls') do set "cls=%%a"
rem If /A switch is not provided, delete the file that receives Tee output
if /I "%~2" neq "/A" if exist %1 del %1
rem Create the semaphore-signal file and start the asynchronous Tee process
echo X > Flag.out
if exist Flag.in del Flag.in
Cscript //nologo //E:JScript "%~F0" | "%~F0" %1 :TeeProcess
del Flag.out
goto :EOF
:TeeProcess
rem Wait for "Data Available" signal
if not exist Flag.in goto TeeProcess
rem Read the line sent by JScript section
set line=
set /P line=
rem Set "Data Read" acknowledgement
ren Flag.in Flag.out
rem Check for the standard "End Of piped File" mark
if "!line!" equ ":_EOF_:" exit /B
rem Correctly manage CLS command
if "!line:~0,1!" equ "!cls!" (
cls
set "line=!line:~1!"
)
rem Duplicate the line in Stdout and the Tee output file
echo(!line!
echo(!line!>> %1
goto TeeProcess
@end
// JScript section
var fso = new ActiveXObject("Scripting.FileSystemObject");
// Process all lines of Stdin
while ( ! WScript.Stdin.AtEndOfStream ) {
// Read the next line from Stdin
var line = WScript.Stdin.ReadLine();
// Wait for "Data Read" acknowledgement
while ( ! fso.FileExists("Flag.out") ) {
WScript.Sleep(10);
}
// Send the line to Batch section
WScript.Stdout.WriteLine(line);
// Set "Data Available" signal
fso.MoveFile("Flag.out", "Flag.in");
}
// Wait for last "Data Read" acknowledgement
while ( ! fso.FileExists("Flag.out") ) {
WScript.Sleep(10);
}
// Send the standard "End Of piped File" mark
WScript.Stdout.WriteLine(":_EOF_:");
fso.MoveFile("Flag.out", "Flag.in");
@echo on
set startDate=%date%
set startTime=%time%
set /a sth=%startTime:~0,2%
set /a stm=1%startTime:~3,2% - 100
set /a sts=1%startTime:~6,2% - 100
fullprocess.bat > C:\LOGS\%startDate%_%sth%.%stm%.%sts%.LOG | fullprocess.bat
سيؤدي ذلك إلى إنشاء ملف سجل مع التاريخ الحالي ، ويمكنك خطوط الأسطر أثناء العملية
هذا هو الاختلاف في السابق الجواب بواسطة MTS ، لكنه يضيف بعض الوظائف التي قد تكون مفيدة للآخرين. إليك الطريقة التي استخدمتها:
set _Temp_Msg_Cmd=
^
بحيث لا يتم تقييم الأوامر في البداية%~n0_temp.txt
والذي يستخدم بناء جملة ملحق معلمة سطر الأوامر%~n0
للحصول على اسم ملف الدُفعات.%~n0_log.txt
هنا تسلسل الأوامر:
^> %~n0_temp.txt 2^>^&1
^& type %~n0_temp.txt ^>^> %~n0_log.txt
^& type %~n0_temp.txt
^& del /Q /F %~n0_temp.txt
هنا هو المثال:
set _Temp_Msg_Cmd= ^> %~n0_temp.txt 2^>^&1 ^& type %~n0_temp.txt ^>^> %~n0_log.txt ^& type %~n0_temp.txt ^& del /Q /F %~n0_temp.txt
بهذه الطريقة يمكن ببساطة إلحاق الأمر بعد الأوامر اللاحقة في ملف دفعي يبدو أكثر نظافة:
echo test message %_Temp_Msg_Cmd%
يمكن إضافة هذا إلى نهاية الأوامر الأخرى أيضًا. بقدر ما أستطيع أن أقول أنها ستعمل عندما يكون للرسائل أسطر متعددة. على سبيل المثال ، يخرج الأمر التالي سطرين إذا كانت هناك رسالة خطأ:
Net Use M: /D /Y %_Temp_Msg_Cmd%
إذا كنت في CLI ، فلماذا لا تستخدم حلقة FOR لـ "DO" لكل ما تريد:
for /F "delims=" %a in ('dir') do @echo %a && echo %a >> output.txt
مورد كبير على Windows CMD للحلقات: https://ss64.com/nt/for_cmd.html المفتاح هنا هو تعيين المحددات (delims) ، والتي من شأنها أن تفكك كل سطر من الإخراج ، إلى شيء. بهذه الطريقة لن ينكسر الافتراضي للمساحة البيضاء. ٪ a عبارة عن خطاب تعسفي ، لكن يتم استخدامه في قسم "do" للقيام ، حسناً ... بعمل شيء باستخدام الأحرف التي تم تحليلها في كل سطر. في هذه الحالة ، يمكننا استخدام علامات الضم (&&) لتنفيذ أمر الصدى الثاني لإنشاء أو إلحاق (>>) بملف من اختيارنا. أكثر أمانًا للحفاظ على هذا الترتيب لأوامر DO في حالة وجود مشكلة في كتابة الملف ، سنحصل على الأقل على الصدى إلى وحدة التحكم أولاً. علامة (@) الموجودة أمام أول صدى تمنع وحدة التحكم من إظهار أمر الارتداد نفسه ، وبدلاً من ذلك فقط تعرض نتيجة الأمر وهي عرض الأحرف في٪ a. خلاف ذلك سترى:
حجم الصدى في محرك الأقراص [x] هو Windows
وحدة التخزين في محرك الأقراص [x] هي Windows
UPDATE:/F يتخطى الأسطر الفارغة والإصلاح الوحيد هو تصفية الخرج مسبقًا بإضافة حرف إلى كل سطر (ربما مع أرقام الأسطر عبر أمر البحث). حل هذا في CLI ليس سريعًا أو جميلًا. أيضًا ، لم أقم بتضمين STDERR ، لذا فإليك التقاط الأخطاء أيضًا:
for /F "delims=" %a in ('dir 2^>^&1') do @echo %a & echo %a >> output.txt
توجد العلامات (^) هناك للهروب من الرموز بعدها ، لأن الأمر عبارة عن سلسلة يتم تفسيرها ، على عكس القول ، بإدخالها مباشرة في سطر الأوامر.
يمكنني استخدام روتين فرعي الدفعي مع عبارة "for" للحصول على سطر الأوامر إخراج سطر واحد في كل مرة وكلاهما كتابة هذا السطر إلى ملف وإخراجها إلى وحدة التحكم.
@echo off
set logfile=test.log
call :ExecuteAndTee dir C:\Program Files
Exit /B 0
:ExecuteAndTee
setlocal enabledelayedexpansion
echo Executing '%*'
for /f "delims=" %%a in ('%* 2^>^&1') do (echo.%%a & echo.%%a>>%logfile%)
endlocal
Exit /B 0
البديل هو أن تضيف stdout إلى stderr ضمن برنامجك:
في جافا:
System.setOut(new PrintStream(new TeeOutputStream(System.out, System.err)));
ثم ، في batchfile dos: Java program > log.txt
سينتقل stdout إلى ملف السجل وسيظهر stderr (نفس البيانات) على وحدة التحكم.
هناك صيغة أخرى تتمثل في تقسيم الأنبوب ، ثم إعادة توجيه الإخراج كما تريد.
@echo off
for /f "tokens=1,* delims=:" %%P in ('findstr /n "^"') do (
echo.%%Q
echo.%%Q>&3
)
@exit/b %errorlevel%
حفظ ما سبق إلى ملف .bat. يقوم بتقسيم إخراج النص على filestream 1 إلى filestream 3 أيضًا ، والذي يمكنك إعادة توجيهه حسب الحاجة. في الأمثلة أدناه ، اتصلت بالبرنامج النصي أعلاه splitPipe.bat ...
dir | splitPipe.bat 1>con 2>&1 3>my_stdout.log
splitPipe.bat 2>nul < somefile.txt
أقوم بتثبيت Perl على معظم أجهزتي لذلك إجابة باستخدام Perl: tee.pl
my $file = shift || "tee.dat";
open $output, ">", $file or die "unable to open $file as output: $!";
while(<STDIN>)
{
print $_;
print $output $_;
}
close $output;
دير | Perl tee.pl أو dir | Perl tee.pl dir.bat
الخام وغير مجربة.
تماما مثل يونيكس.
dir | tee a.txt
يعمل على نظام التشغيل Windows XP ، يتطلب تثبيت mksnt
.
يتم عرضه على موجه وكذلك إلحاق الملف.
هذا يعمل في الوقت الحقيقي ولكن أيضا بشع والأداء بطيء. لم يتم اختباره بشكل جيد أيضًا:
@echo off
cls
SET MYCOMMAND=dir /B
ECHO File called 'test.bat' > out.txt
for /f "usebackq delims=" %%I in (`%MYCOMMAND%`) do (
ECHO %%I
ECHO %%I >> out.txt
)
pause
كيف يمكنني عرض وإعادة توجيه الإخراج إلى ملف. لنفترض أنه في حالة استخدام الأمر dos ، dir> test.txt ، سيعيد هذا الأمر توجيه الإخراج إلى ملف test.txt دون عرض النتائج. كيفية كتابة أمر لعرض الإخراج وإعادة توجيه الإخراج إلى ملف باستخدام DOS ، على سبيل المثال ، windows command Prompt ، وليس في UNIX/LINUX.
قد تجد هذه الأوامر في biterscripting ( http://www.biterscripting.com ) مفيدة.
var str output
lf > $output
echo $output # Will show output on screen.
echo $output > "test.txt" # Will write output to file test.txt.
system start "test.txt" # Will open file test.txt for viewing/editing.
يساعدك المتابعة إذا كنت تريد شيئًا ما يظهر بالفعل على الشاشة - حتى إذا تمت إعادة توجيه الملف الدفعي إلى ملف. ربما يستخدم الجهاز CON أيضًا في حالة إعادة توجيهه إلى ملف
مثال:
ECHO first line on normal stdout. maybe redirected
ECHO second line on normal stdout again. maybe redirected
ECHO third line is to ask the user. not redirected >CON
ECHO fourth line on normal stdout again. maybe redirected
انظر أيضًا وصفًا جيدًا لإعادة التوجيه: http://www.p-dd.com/chapter7-page14.html