我目前有一个非常简单的脚本,它会ping 10个IP:
@ECHO OFF
for /L %%i in (100, 1, 110) DO (
START /W /B cmd /c ping -n 1 192.168.0.%%i | find "time="
)
输出符合预期:
C:\Users\herpderp>test.bat Reply from 192.168.0.101: bytes=32 time=294ms TTL=64 Reply from 192.168.0.104: bytes=32 time=1ms TTL=64
然而,它非常缓慢并且肯定会顺序发生。当我使用PowerShell Measure-Command
运行时,我得到了以下结果:
PS C:\Users\derpherp> measure-command {start-process test.bat -Wait} Days : 0 Hours : 0 Minutes : 0 Seconds : 23 Milliseconds : 107 Ticks : 231074173 TotalDays : 0.000267446959490741 TotalHours : 0.00641872702777778 TotalMinutes : 0.385123621666667 TotalSeconds : 23.1074173 TotalMilliseconds : 23107.4173
所以我们看到它需要大约23秒才能执行。
现在,如果我在Linux系统上并希望做同样的事情,我可以做到以下几点:
#!/bin/bash
for ip in $(seq 100 110); do
ping -c 1 192.168.0.$ip | grep "bytes from" | cut -d" " -f4 | cut -d ":" -f1 &
done
结果有多种不同:
结果并不总是顺序的,这意味着它实际上更加异步地启动命令:
root@kali:~/vids/bash_scripting# ./test.sh 192.168.0.104 192.168.0.100 192.168.0.103 192.168.0.101
显示所有正面结果的时间通常不到一秒,这可以扩展到更大的数字集。
所以,我的问题是,这是批量脚本的限制吗?我觉得很难相信bash在执行如此简单的任务时比Windows CMD解释器的表现要好几十倍?
如果这是有限的,PowerShell是否提供了创建任务的有竞争力的方法?我在foreach循环中使用了Start-Job
但是对于大量任务(即/ 16网络上的Test-Connection
)似乎变得不可行了
修改1
@ECHO OFF
for /L %%i in (100, 1, 110) DO (
ping -n 1 192.168.0.%%i | find "time="
)
这将输出当前窗口,并且与初始变量
一样长@ECHO OFF
for /L %%i in (100, 1, 110) DO (
START ping -n 1 192.168.0.%%i | find "time="
)
这将输出到每个IP的唯一窗口,并且需要很长时间才能完成。
答案 0 :(得分:4)
异步并不容易,但使用PowerShell可以很容易地完成工作。
此代码应该表现出您的bash代码的样子,返回所有响应的IP地址而不会出错:
$IPAddresses = 100..110 | ForEach-Object { "192.168.0.$_"; }
$JobList = $IPAddresses | ForEach-Object {
Test-Connection -ComputerName $_ -Count 1 -AsJob;
}
Receive-Job -Job $JobList -AutoRemoveJob -Wait | `
Where-Object { $_.StatusCode -eq 0 } | `
Select-Object -ExpandProperty Address;
以上完成了我在3秒钟内对抗~250个主机。
Test-Connection
本身声称最多可同时使用32个连接(可使用-ThrottleLimit
设置进行配置)但如果您要定位,-Delay
选项似乎完全会覆盖该设置范围很广。
PowerShell v4及更早版本可能存在问题,因为它的行为可能略有不同。 Test-Connection
特别是在不同版本的Windows或PowerShell上似乎是特殊的。至少,我总是记得抛出错误,而不是在以前的版本中返回错误状态代码。
如果你想要比Test-Connection
给你的更好的谷物控制 - 例如,它默认为1秒超时,所以你在任何主机关闭时等待的最短时间是1第二 - 你可能不得不恢复直接呼叫Get-WMIObject -Query "SELECT * FROM Win32_PingStatus WHERE Address = '$IP' AND TimeOut = 200" -AsJob
。
答案 1 :(得分:2)
似乎我找到了一个纯粹的batch-file解决方案。基本上,脚本同时触发几个ping
命令,这些命令都将结果写入各个日志文件;监视这些文件的写访问权限,因为只要相应的ping
进程正在进行,文件就会被写锁定;只要授予写访问权限,包含IP地址的日志文件的第一行就会被复制到摘要日志文件中。所以这是代码 - 请参阅所有解释性rem
备注:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Predefine IP addresses as an array:
for /L %%J in (0,1,5) do (
set "IP[%%J]=127.0.0.%%J"
)
rem // Ping IP addresses simultaneously, create individual log files:
for /F "tokens=2,* delims=[=]" %%J in ('set IP[') do (
start "" /B cmd /C ping -n 2 %%K ^| find "TTL=" ^> "%~dpn0_%%J.log"
)
rem // Deplete summary log file:
> "%~dpn0.log" rem/
rem /* Polling loop to check whether individual log files are accessible;
rem this works, because a pinging process is not yet finished, the
rem respective log file is still opened and therefore write-locked: */
:POLL
rem // Give processor some time:
> nul timeout /T 1 /NOBREAK
rem /* Loop through all available array elements; for every accomplished
rem pinging process, the related array element becomes deleted, so
rem finally, there should not be any more array elements defined: */
for /F "tokens=2 delims=[=]" %%J in ('2^> nul set IP[') do (
rem // Suppress error message in case log file is write-locked:
2> nul (
rem // Try to append nothing to the log file:
>> "%~dpn0_%%J.log" rem/ && (
rem /* Appending succeeded, hence log file is no longer locked
rem and the respective pinging process has been finished;
rem therefore read the first line containing the IP: */
set "FILE=" & set "IP="
< "%~dpn0_%%J.log" set /P IP=""
rem // Copy the read line to the summary log file:
if defined IP >> "%~dpn0.log" call echo(%%IP%%
rem // Undefine related array element:
set "IP[%%J]="
rem // Store log file path for later deletion:
set "FILE=%~dpn0_%%J.log"
)
rem // Delete individual log file finally:
if defined FILE call del "%%FILE%%"
)
)
rem // Jump to polling loop in case there are still array elements:
> nul 2>&1 set IP[ && goto :POLL
endlocal
exit /B
答案 2 :(得分:1)
您不需要start
命令。你关闭了它的所有功能。然后你告诉它为CMD
开始一个新的过程,这个过程很慢且没必要。所以 - ping -n 1 192.168.0.%%i |find "time="
。
请参阅我的摘要,了解如何启动程序 - What do all commands in batch mean and do?。
您可以使用start并行运行ping
,但是您需要删除/w
,这意味着等待(但因为被忽略)和/b
#39;在新生成的进程中运行该命令,但是按顺序执行。
由于您仍在进行Ping
的多个流程创建,因此您可以使用WMIC来避免这种情况并测试一个流程中的所有计算机。
wmic /node:@"c:\computerlist.txt" /append:"textfile.txt" path win32_pingstatus where "address='127.0.0.1' and responsetime > 100" get responsetime,timestamprecord
。
所以我们已经从20个流程创建到1。
在编程中,我们必须支付系统开销税。 Windows在Process Creation和Window Creation中收取大部分税。这是为了允许在没有太多系统开销的情况下进行其他操作。一个例子是Windows保留正在运行的进程表 - 在创建进程时使用资源进行更新,但允许快速查找其他操作。