Utils/touch.ps1
|
Register-GnuUtil @{ Name = 'touch' Category = 'File and directory operations' Synopsis = 'Change file timestamps.' Usage = @('touch [OPTION]... FILE...') Description = @( 'Update the access and modification times of each FILE to the current time.', '', 'A FILE argument that does not exist is created empty, unless -c or -h is supplied.', '', 'A FILE argument string of - is handled specially and causes touch to', 'change the times of the file associated with standard output.' ) FileOperands = $true Options = @( @{ Short = 'a'; Key = 'access'; Help = 'change only the access time' } @{ Short = 'c'; Long = 'no-create'; Help = 'do not create any files' } @{ Short = 'd'; Long = 'date'; Arg = 'STRING'; Help = 'parse STRING and use it instead of current time' } @{ Short = 'f'; Help = '(ignored)' } @{ Short = 'h'; Long = 'no-dereference'; Help = 'affect each symbolic link instead of any referenced file (useful only on systems that can change the timestamps of a symlink)' } @{ Short = 'm'; Key = 'modify'; Help = 'change only the modification time' } @{ Short = 'r'; Long = 'reference'; Arg = 'FILE'; Help = 'use this file''s times instead of current time' } @{ Short = 't'; Key = 'stamp'; Arg = 'STAMP'; Help = 'use [[CC]YY]MMDDhhmm[.ss] instead of current time' } @{ Long = 'time'; Arg = 'WORD'; Help = 'change the specified time: WORD is access, atime, or use: equivalent to -a; WORD is modify or mtime: equivalent to -m' } ) Notes = @( 'PowerShell notes: -d understands @SECONDS, now/today/yesterday/tomorrow, ISO 8601 and other', 'invariant-culture dates, and relative items such as "2 days ago" or "+3 hours" (not all of GNU''s grammar).', 'The - operand (standard output) is ignored. -h does not create missing files; .NET sets the times of', 'a link''s target.' ) } function script:Invoke-GnuTouchFile { <# .SYNOPSIS Implementation of touch. #> param([Parameter(Mandatory)][hashtable]$Context) $operands = @($Context.Operands) if ($operands.Count -eq 0) { Write-GnuUsageError -Context $Context -Message 'missing file operand' return } $setAccess = Test-GnuOption -Context $Context -Key 'access' $setModify = Test-GnuOption -Context $Context -Key 'modify' if (Test-GnuOption -Context $Context -Key 'time') { $word = [string](Get-GnuOptionValue -Context $Context -Key 'time') switch -Regex ($word) { '^(access|atime|use)$' { $setAccess = $true } '^(modify|mtime)$' { $setModify = $true } default { Write-GnuUsageError -Context $Context -Message "invalid argument '$word' for '--time'`nValid arguments are: 'atime', 'access', 'use', 'mtime', 'modify'" return } } } if (-not $setAccess -and -not $setModify) { $setAccess = $true $setModify = $true } if ((Test-GnuOption -Context $Context -Key 'date') -and (Test-GnuOption -Context $Context -Key 'stamp')) { Write-GnuUsageError -Context $Context -Message 'cannot specify times from more than one source' return } $now = [datetime]::Now $accessTime = $now $modifyTime = $now if (Test-GnuOption -Context $Context -Key 'reference') { $referenceName = [string](Get-GnuOptionValue -Context $Context -Key 'reference') $reference = Get-Item -LiteralPath (Resolve-GnuPath -Path $referenceName) -Force -ErrorAction SilentlyContinue if ($null -eq $reference) { Write-GnuError -Context $Context -Message "failed to get attributes of '$referenceName': No such file or directory" return } $accessTime = $reference.LastAccessTime $modifyTime = $reference.LastWriteTime } if (Test-GnuOption -Context $Context -Key 'date') { $text = [string](Get-GnuOptionValue -Context $Context -Key 'date') # GNU: with -r, relative dates are relative to the reference file's modification time. $parsed = ConvertFrom-GnuDateString -Text $text -Now $modifyTime if ($null -eq $parsed) { Write-GnuError -Context $Context -Message "invalid date format '$text'" return } $accessTime = $parsed $modifyTime = $parsed } if (Test-GnuOption -Context $Context -Key 'stamp') { $stamp = [string](Get-GnuOptionValue -Context $Context -Key 'stamp') $parsed = ConvertFrom-GnuTouchStamp -Stamp $stamp if ($null -eq $parsed) { Write-GnuError -Context $Context -Message "invalid date format '$stamp'" return } $accessTime = $parsed $modifyTime = $parsed } $noCreate = (Test-GnuOption -Context $Context -Key 'no-create') -or (Test-GnuOption -Context $Context -Key 'no-dereference') foreach ($name in $operands) { if ($name -eq '-') { continue } $path = Resolve-GnuPath -Path $name if (-not [System.IO.File]::Exists($path) -and -not [System.IO.Directory]::Exists($path)) { if ($noCreate) { continue } try { $stream = New-Object System.IO.FileStream -ArgumentList $path, ([System.IO.FileMode]::OpenOrCreate), ([System.IO.FileAccess]::Write) $stream.Dispose() } catch { Write-GnuError -Context $Context -Message "cannot touch '$name': $(Get-GnuErrorReason -Exception $_.Exception)" continue } } try { $item = Get-Item -LiteralPath $path -Force if ($setAccess) { $item.LastAccessTime = $accessTime } if ($setModify) { $item.LastWriteTime = $modifyTime } } catch { Write-GnuError -Context $Context -Message "setting times of '$name': $(Get-GnuErrorReason -Exception $_.Exception)" } } } |