是否有任何简单的方法(即脚本)在powershell中查看文件并在文件更改时运行命令。我一直在谷歌搜索,但找不到简单的解决方案。基本上我在powershell中运行脚本,如果文件发生了变化,那么powershell会运行其他命令。
修改
好吧我觉得我搞错了。我不需要脚本,一个我可以包含在$PROFILE.ps1
文件中的需要函数。但是,我仍然很努力,我仍然无法写出来,所以我会给予赏金。它必须如下所示:
function watch($command, $file) {
if($file #changed) {
#run $command
}
}
有一个npm模块正在做我想要的事情watch
,但它只监视文件夹而不是文件,而不是PowerShell xD。
答案 0 :(得分:25)
以下是我在代码段中找到的示例。希望它更全面一点。
首先,您需要创建一个文件系统观察程序,然后您订阅观察者正在生成的事件。此示例侦听“创建”事件,但可以轻松修改以注意“更改”。
$folder = "C:\Users\LOCAL_~1\AppData\Local\Temp\3"
$filter = "*.LOG"
$Watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property @{
IncludeSubdirectories = $false
NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
}
$onCreated = Register-ObjectEvent $Watcher Created -SourceIdentifier FileCreated -Action {
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp"
Write-Host $path
#Move-Item $path -Destination $destination -Force -Verbose
}
我会尝试将其缩小到您的要求。
如果您将此作为" profile.ps1"的一部分运行脚本你应该阅读The Power of Profiles,它解释了可用的不同配置文件脚本等等。
此外,您应该了解等待文件夹中的更改无法作为脚本中的函数运行。必须完成配置文件脚本才能启动PowerShell会话。但是,您可以使用函数来注册事件。
这样做,就是注册一段代码,每次触发事件时都要执行。当会话保持打开状态时,此代码将在当前PowerShell主机(或shell)的上下文中执行。它可以与主机会话交互,但不知道注册代码的原始脚本。在您的代码被触发时,原始脚本可能已经完成。
以下是代码:
Function Register-Watcher {
param ($folder)
$filter = "*.*" #all files
$watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property @{
IncludeSubdirectories = $false
EnableRaisingEvents = $true
}
$changeAction = [scriptblock]::Create('
# This is the code which will be executed every time a file change is detected
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file $name was $changeType at $timeStamp"
')
Register-ObjectEvent $Watcher "Changed" -Action $changeAction
}
Register-Watcher "c:\temp"
运行此代码后,更改" C:\ temp"中的任何文件。目录(或您指定的任何其他目录)。您将看到一个触发代码执行的事件。
此外,您可以注册的有效FileSystemWatcher事件是"已更改","已创建","已删除"和#34;重命名"。
答案 1 :(得分:6)
我会添加另一个答案,因为我之前的答案确实错过了要求。
要求
使用文件哈希已有答案。我想按照我之前的回答,向您展示如何使用FileSystemWatcher实现这一目标。
$File = "C:\temp\log.txt"
$Action = 'Write-Output "The watched file was changed"'
$global:FileChanged = $false
function Wait-FileChange {
param(
[string]$File,
[string]$Action
)
$FilePath = Split-Path $File -Parent
$FileName = Split-Path $File -Leaf
$ScriptBlock = [scriptblock]::Create($Action)
$Watcher = New-Object IO.FileSystemWatcher $FilePath, $FileName -Property @{
IncludeSubdirectories = $false
EnableRaisingEvents = $true
}
$onChange = Register-ObjectEvent $Watcher Changed -Action {$global:FileChanged = $true}
while ($global:FileChanged -eq $false){
Start-Sleep -Milliseconds 100
}
& $ScriptBlock
Unregister-Event -SubscriptionId $onChange.Id
}
Wait-FileChange -File $File -Action $Action
答案 2 :(得分:4)
您可以使用System.IO.FileSystemWatcher
来监控文件。
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = $searchPath
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true
答案 3 :(得分:3)
function watch($f, $command, $interval) {
$sha1 = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider
$hashfunction = '[System.BitConverter]::ToString($sha1.ComputeHash([System.IO.File]::ReadAllBytes($file)))'
$files = @{}
foreach ($file in $f) {
$hash = iex $hashfunction
$files[$file.Name] = $hash
echo "$hash`t$($file.FullName)"
}
while ($true) {
sleep $interval
foreach ($file in $f) {
$hash = iex $hashfunction
if ($files[$file.Name] -ne $hash) {
iex $command
}
}
}
}
使用示例:
$c = 'send-mailmessage -to "admin@whatever.com" -from "watch@whatever.com" -subject "$($file.Name) has been altered!"'
$f = ls C:\MyFolder\aFile.jpg
watch $f $c 60
答案 4 :(得分:3)
这是我最终得到的解决方案,基于以前的几个答案。我特别想要:
旁注:由于使用全局变量在线程之间进行通信具有讽刺意味,因此我可以编写Erlang代码。
我已经留下了我想要运行的细节。Function RunMyStuff {
# this is the bit we want to happen when the file changes
Clear-Host # remove previous console output
& 'C:\Program Files\erl7.3\bin\erlc.exe' 'program.erl' # compile some erlang
erl -noshell -s program start -s init stop # run the compiled erlang program:start()
}
Function Watch {
$global:FileChanged = $false # dirty... any better suggestions?
$folder = "M:\dev\Erlang"
$filter = "*.erl"
$watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property @{
IncludeSubdirectories = $false
EnableRaisingEvents = $true
}
Register-ObjectEvent $Watcher "Changed" -Action {$global:FileChanged = $true} > $null
while ($true){
while ($global:FileChanged -eq $false){
# We need this to block the IO thread until there is something to run
# so the script doesn't finish. If we call the action directly from
# the event it won't be able to write to the console
Start-Sleep -Milliseconds 100
}
# a file has changed, run our stuff on the I/O thread so we can see the output
RunMyStuff
# reset and go again
$global:FileChanged = $false
}
}
RunMyStuff # run the action at the start so I can see the current output
Watch
如果你想要更通用的东西,你可以将文件夹/过滤器/动作传递给观察。希望这对其他人来说是一个有用的起点。
答案 5 :(得分:2)
我有类似的问题。我首先想要使用Windows事件并进行注册,但这样下的解决方案的容错性会降低 我的解决方案是一个轮询脚本(间隔为3秒)。该脚本在系统上具有最小的占用空间,并且通知变化非常快。在循环中我的脚本可以做更多的事情(实际上我检查3个不同的文件夹)。
我的轮询脚本是通过任务管理器启动的。计划从每5分钟开始,标志停止 - 已经运行。这样它会在重启后或崩溃后重新启动 对于任务管理器来说,使用任务管理器每3秒进行一次轮询非常频繁。 向调度程序添加任务时,请确保不使用网络驱动器(这将需要额外的设置)并为您的用户授予批量权限。
我在午夜前几分钟关闭它,让我的脚本干净利落。任务管理器每天早上启动脚本(我的脚本的init函数将在午夜左右退出)。
答案 6 :(得分:0)
这是另一种选择。
我只需编写自己的内容即可在Docker容器中观看和运行测试。 Jan的解决方案更优雅,但FileSystemWatcher目前在Docker容器中被破坏。我的方法与Vasili相似,但更加懒惰,相信文件系统的写入时间。
这是我需要的功能,每次文件更改时都会运行命令块。
function watch($command, $file) {
$this_time = (get-item $file).LastWriteTime
$last_time = $this_time
while($true) {
if ($last_time -ne $this_time) {
$last_time = $this_time
invoke-command $command
}
sleep 1
$this_time = (get-item $file).LastWriteTime
}
}
这是一个等待文件更改,运行块然后退出的文件。
function waitfor($command, $file) {
$this_time = (get-item $file).LastWriteTime
$last_time = $this_time
while($last_time -eq $this_time) {
sleep 1
$this_time = (get-item $file).LastWriteTime
}
invoke-command $command
}