Страница 3 из 3

Добавлено: Сб май 26, 2018 19:30
helb
Обновил. Там какие-то изменения, что уже не помню (вроде параллелизм получше) и свежая новая опция с поддержкой переноса атрибутов с оригинальных файлов на результат.
[cut="MultiRun.ps1"]

Код: Выделить всё

<#	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"
[/cut]