Тема: CMD/BAT: дублирование вывода команды (обсуждение)
Коллега Poltergeyst в теме CMD/BAT: дублирование вывода команды поделился своим вариантом реализации команды tee из мира unix. Тема открыта в разделе Коллекции, поэтому обсуждение здесь, отдельной темой.
Я тоже задавался вопросом "а не сделать ли и мне что-то подобное" на чистом батнике, но мне было лень. А еще я видел весьма интересные, но несколько запутанные и ограниченные решения. Например, здесь: Asynchronous native batch tee script. И там используется временный файл, что, на мой взгляд, не очень хорошо.
Я решил попробовать реализовать свое видение и немного дополнить его так, чтобы приблизить к возможностям исходной команды. Выглядит это так:
C:\>tee
Usage: tee [/a] [FILE]...
Copy STDIN to each file and also to STDOUT
/a Append to the given files, don't overwrite
Преимущества данного подхода:
1. возможность писать сразу в несколько файлов
2. возможность дописывать в существующие файлы (ключ /A)
0</*! ::
::>Usage: tee [/a] [FILE]...
::>
::>Copy STDIN to each file and also to STDOUT
::>
::>/a Append to the given files, don't overwrite
@echo off
timeout /t 0 >nul 2>&1 && (
for /f "tokens=1,* delims=>" %%a in ( 'findstr "^::>" "%~f0"' ) do echo:%%b
goto :EOF
)
cscript //nologo //e:javascript "%~f0" %*
goto :EOF
*/0;
// Declare synonyms and references to the global WSH objects
var stdin = WScript.StdIn;
var stdout = WScript.StdOut;
var stderr = WScript.StdErr;
var nargs = WScript.Arguments.Named;
var uargs = WScript.Arguments.Unnamed;
var fso = new ActiveXObject('Scripting.FileSystemObject');
// Constants
var F_MODE_WRITE = 2;
var F_MODE_APPEND = 8;
var F_FORMAT_DEFAULT = -2;
// Append or overwrite
var append = nargs.Exists('A');
// STDOUT is one of the targets
var files = [ {
filename: '<stdout>',
handler: stdout
} ];
for (var i = 0; i < uargs.length; i++) {
var e;
try {
var f = uargs.item(i);
var h = fso.OpenTextFile(
f,
append ? F_MODE_APPEND : F_MODE_WRITE,
true,
F_FORMAT_DEFAULT);
files.push({
filename: f,
handler: h
});
} catch(e) {
// Don't stop execution, just report the problem and continue
stderr.WriteLine([
WScript.ScriptName,
f,
e.description
].join(': '));
}
}
// Read STDIN line by line and put each line to all available targets
while ( ! stdin.AtEndOfStream ) {
var line = stdin.ReadLine();
for (var i = 0; i < files.length; i++) {
files[i].handler.WriteLine(line);
}
}
// Let's close all files gracefully
for (var i = 1; i < files.length; i++) {
files[i].handler.Close();
}
Наконец-то задумался о названии программы. Оказывается оно возникло из-за сходства с тройниками (синонимы: фитинг, т-образный переходник или т-образный разветвитель) и их функционалом (один поток развести на два направления). В английском их называют t-splitter и произносят, соответственно, [tee]. Отсюда и название программы.