<# MultiRun [by helb] v2018-05-26
Launches specified command for every item in a list (file paths or any arbitrary data in formatted lines). Supports RegEx.
Command line usage: powershell <this script pathname> <listfile> [-re '<regex with capture groups>'] [-threads <number>] [-copyattributes '<regex of source file (with mandatory capture group) from resulting command line>:::<regex of output file>'] <command> '<command parameters>'
Match and captured groups should be represented in command with number after ‘:::’ signs (e.g. ‘:::2’)
Any ‘"’ characters inside command arguments should be escaped with ‘"""’ or ‘\"’, arguments containing ‘&’ should be additionlly quoted like '"<text with &>"' (e.g. '"-arg=\"weird&unu$ual\""')
Total Commander file list parameter: %UL
Запускает указанную команду для каждой записи в списке (пути файлов или любые произвольные данные форматированными строками). Поддерживает RegEx.
Использование: powershell <путь скрипта> <лист-файл> [-re '<regex включая capture-группы>'] [-threads <число>] [-copyattributes '<regex исходного файла (с обязательной capture-группой) из результирующей командной строки>:::<regex выходного>'] <команда> '<параметры команды>'
Регулярное выражение и захваченные группы должны быть представлены в команде в виде «:::номер» (например «:::2»)
Любые символы «"» внутри аргументов команды требуется представить в виде «"""» или «\"», аргументы содержащие «&» дополнительно заключить в «"» '"подобным образом"' (например: '"-arg=\"weird&unu$ual\""')
Параметр в Total Commander для списка файлов: %UL
Example, mux youtube video in separate video (.mp4) and audio (.m4a) dash-files into normal mp4 container and copy timestamps from audio files:
powershell MultiRun.ps1 video-only-files-list.txt -threads 4 -re '(.+)\.mp4$' -copyattr '\"(.+?\.m4a)\":::\"(.+?~\.mp4)\"' ffmpeg.exe '-i ":::0" -i ":::1.m4a" -c copy -map 0:v:0 -map 1:a:0 ":::1~.mp4"'
#>
Param
(
[parameter(Position=0, Mandatory=$true)][string]$list,
[string]$re,
[int]$threads,
[string]$copyattributes,
[parameter(ValueFromRemainingArguments=$true)][string[]]$arguments
)
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
function msgBx($text, $title, $btns = 0) {
return [System.Windows.Forms.MessageBox]::Show($text, $title, $btns)
}
function getAttr($filename) {
$f = get-item -literalPath $filename
$a = ($f | select FullName, @{E={$_.CreationTime.ToString('s')};L="CreationTime"}, @{E={$_.LastWriteTime.ToString('s')};L="LastWriteTime"}, @{E={$_.LastAccessTime.ToString('s')};L="LastAccessTime"}, Attributes )
return $a
}
if (!$list) { msgBx "No list specified." "Error"; return }
if (!$threads -or $threads -lt 1) { $threads = 1 }
$list = [environment]::ExpandEnvironmentVariables($list)
if (!(test-path -literalPath $list)) { msgBx ("List file not found.`n" + $list) "Warning"; return }
$arguments
[string]$clinebase = $arguments[1..($arguments.length-1)] -join ' '
# $clinebase
if ($copyattributes) {
[array]$copyattributes = $copyattributes -split ':::'
}
$jobs = @()
for ($i = 0; $i -lt $threads; $i++) {
$jobs += $null
}
get-content $list | foreach {
$cline = $clinebase -replace ':::0', $_
if ($re -and $_ -match $re) {
for ($i = 1; $i -lt $matches.count; $i++){
$cline = $cline.replace(':::' + $i, $matches[$i])
}
}
$cline
if ($copyattributes) {
$nameIn = $nameOut = ''
$attr = $null
if ($cline -match $copyattributes[0]) { $nameIn = $matches[1] }
if ($cline -match $copyattributes[1]) { $nameOut = $matches[1] }
if ($nameIn -and $nameOut) {
$attr = getAttr($nameIn)
if ($attr) { $attr.FullName = $nameOut }
write-host "nameIn : $nameIn"
write-host "nameOut : $nameOut"
}
}
do {
$launched = $false
for ($i = 0; $i -lt $threads; $i++) {
if ($jobs[$i] -and $jobs[$i].HasExited) {
$jobs[$i].Dispose()
$jobs[$i] = $null
}
if ($jobs[$i] -eq $null) {
$jobs[$i] = Start-Process $arguments[0] -PassThru -ArgumentList $cline
if ($copyattributes -and $attr) {
# $jobs[$i] | Add-Member -MemberType NoteProperty -Name "savedAttr" -Value $attr
$evt = Register-ObjectEvent -InputObject $jobs[$i] -EventName Exited -MessageData $attr -Action {
function setAttr($a, $name = '') {
if (!$name) { $name = $a.FullName }
write-host "restoring attributes of [$name]"
if (test-path -literalPath $name) {
$file = get-item -literalPath $name -force
if ($file.IsReadOnly -eq $true -or $file.IsReadOnly -eq $false) { $file.IsReadOnly = $false }
$file.CreationTime = $a.CreationTime
$file.LastWriteTime = $a.LastWriteTime
$file.LastAccessTime = $a.LastAccessTime
$file.Attributes = $a.Attributes
}
}
setAttr($event.MessageData)
}
}
$launched = $true
break
}
}
if (!$launched) { Start-Sleep -m 100 }
} until ($launched)
}
if ($copyattributes) {
do {
$running = 0
foreach ($j in $jobs) {
if ($j -and !$j.HasExited) { $running++ }
}
} until ($running -eq 0)
}
# read-host -prompt "press enter to exit"
|