使用start子命令改进批处理文件以进行循环 [英] Improving Batch File for loop with start subcommand

查看:95
本文介绍了使用start子命令改进批处理文件以进行循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前有一个非常简单的脚本,可以ping通10个IP:

I've currently got a very simple script which pings 10 IPs:

@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运行它时,得到以下结果:

However, it is VERY slow and definitely happening sequentially. When I run this with a PowerShell Measure-Command I get these results:

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秒的时间来执行.

So we see it is taking ~23 seconds to execute.

现在,如果我在Linux系统上并且想做同样的事情,则可以执行以下操作:

Now, if I were on a Linux system and wanted to do this same thing, I can do the following:

#!/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

结果在很多方面都不同:

The result is different in a variety of ways:

  • 结果并不总是顺序的,这意味着它实际上以更异步的方式启动了命令:

  • The results aren't always sequential, meaning it actually started the commands more asynchronously:

root@kali:~/vids/bash_scripting# ./test.sh
192.168.0.104
192.168.0.100
192.168.0.103
192.168.0.101

  • 显示所有阳性结果的时间通常少于一秒钟,并且可以缩放到更大的数字集.

  • The time for it to display all of the positive results is typically less than a second and this scales to much larger sets of numbers.

    所以,我的问题是,这是批处理脚本的限制吗?我发现很难相信bash在如此简单的任务上比Windows CMD解释器的性能好100倍?

    So, my question, is this a limitation of batch scripting? I find it hard to believe that bash performs literally 100s of times better than Windows CMD interpreter for such a simple task?

    如果有此限制,PowerShell是否提供竞争性方法来创建任务?我在foreach循环中使用过Start-Job,但是对于大量任务(即/16网络上的Test-Connection)来说似乎变得不可行

    If this is limited, does PowerShell offer a competitive way to create tasks? I've used Start-Job in a foreach loop but that seems to become unworkable for large numbers of tasks (ie Test-Connection on a /16 network)

    编辑1

    @ECHO OFF
    for /L %%i in (100, 1, 110) DO (
      ping -n 1 192.168.0.%%i | find "time="
    )
    

    这将输出当前窗口,并花费与初始变体一样长的时间

    This outputs the current window and takes just as long as the initial variant

    @ECHO OFF
    for /L %%i in (100, 1, 110) DO (
      START ping -n 1 192.168.0.%%i | find "time="
    )
    

    这将输出到每个IP唯一的窗口,并且只需花费很长时间即可完成.

    This outputs to unique windows per IP and takes just as long to complete.

    推荐答案

    异步并不容易,但是通过作业,您可以使用PowerShell轻松关闭.

    Asynchronous isn't easy, but with jobs you can get close pretty easily with PowerShell.

    此代码的行为应与您的bash代码一样,返回所有无错误响应的主机的IP地址:

    This code should behave how it looks like your bash code does, returning the IP address of all hosts that respond without error:

    $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个主机,以上对我而言是完整的.

    The above completes for me against ~250 hosts in 3 seconds.

    Test-Connection本身声称最多使用32个同时连接(可通过-ThrottleLimit设置进行配置),但是如果您要定位的范围很广,则-Delay选项似乎可以完全覆盖该设置.

    Test-Connection itself claims to use up to 32 simultaneous connections (configurable with -ThrottleLimit setting) but it sure seems like the -Delay option completely overrides that setting if you're targeting a wide range.

    PowerShell v4和更低版本可能会出现问题,因为它的行为可能略有不同. Test-Connection尤其在Windows或PowerShell的不同版本上似乎是特质的.至少,我始终记得它抛出一个错误,而不是在以前的版本中返回错误状态代码.

    You may have issues with PowerShell v4 and earlier, as it may behave slightly differently. Test-Connection in particular seems to be idiosyncratic on different versions of Windows or PowerShell. At least, I always remember it throwing an error instead of returning an error status code in previous versions.

    如果您想对ping进行更精细的控制,而不是Test-Connection给您提供-例如,它默认为1秒超时,因此当任何主机关闭时您要等待的最短时间为1秒-您可能必须恢复为直接调用Get-WMIObject -Query "SELECT * FROM Win32_PingStatus WHERE Address = '$IP' AND TimeOut = 200" -AsJob.

    If you want more fine grain control over the ping than Test-Connection gives you -- for example, it defaults to a 1 second timeout so the minimum time you'll wait when any host is down is 1 second -- you'll probably have to revert to directly calling Get-WMIObject -Query "SELECT * FROM Win32_PingStatus WHERE Address = '$IP' AND TimeOut = 200" -AsJob.

    这篇关于使用start子命令改进批处理文件以进行循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆