14

从这里的这个主题开始,我试图从建议的答案中了解“幕后”发生的事情。我不明白 2>nul 或 1>nul 应该做什么。我试图破译 start /b 行中的符号在做什么,但我在这里真的一无所知。如果你不介意的话,我需要一步一步地解决这个问题。

这部分代码发生了什么?

    2>nul del %lock%!nextProc!
    %= Redirect the lock handle to the lock file. The CMD process will     =%
    %= maintain an exclusive lock on the lock file until the process ends. =%
    start /b "" cmd /c %lockHandle%^>"%lock%!nextProc!" 2^>^&1 !cpu%%N! !cmd!
  )
  set "launch="

和这个:

    ) 9>>"%lock%%%N"
  ) 2>nul
  if %endCount% lss %startCount% (
    1>nul 2>nul ping /n 2 ::1
    goto :wait
  )

2>nul del %lock%*

建议代码的完整副本:

@echo off
setlocal enableDelayedExpansion

:: Display the output of each process if the /O option is used
:: else ignore the output of each process
if /i "%~1" equ "/O" (
  set "lockHandle=1"
  set "showOutput=1"
) else (
  set "lockHandle=1^>nul 9"
  set "showOutput="
)

:: Define the maximum number of parallel processes to run.
:: Each process number can optionally be assigned to a particular server
:: and/or cpu via psexec specs (untested).
set "maxProc=8"

:: Optional - Define CPU targets in terms of PSEXEC specs
::           (everything but the command)
::
:: If a cpu is not defined for a proc, then it will be run on the local machine.
:: I haven't tested this feature, but it seems like it should work.
::
:: set cpu1=psexec \\server1 ...
:: set cpu2=psexec \\server1 ...
:: set cpu3=psexec \\server2 ...
:: etc.

:: For this demo force all cpu specs to undefined (local machine)
for /l %%N in (1 1 %maxProc%) do set "cpu%%N="

:: Get a unique base lock name for this particular instantiation.
:: Incorporate a timestamp from WMIC if possible, but don't fail if
:: WMIC not available. Also incorporate a random number.
  set "lock="
  for /f "skip=1 delims=-+ " %%T in ('2^>nul wmic os get localdatetime') do (
    set "lock=%%T"
    goto :break
  )
  :break
  set "lock=%temp%\lock%lock%_%random%_"

:: Initialize the counters
  set /a "startCount=0, endCount=0"

:: Clear any existing end flags
  for /l %%N in (1 1 %maxProc%) do set "endProc%%N="

:: Launch the commands in a loop
  set launch=1
  echo mem=1m 2m 3m 4m 6m 8m 12m 16m 24m 32m 48m 64m 96m 128m 192m 256m 384m 512m 768m 1024m
  echo o=2 3 4 5 6 7 8 10 12 14 16 20 24 28 32
  echo s=off 1m 2m 4m 8m 16m 32m 64m 128m 256m 512m 1g 2g 4g 8g 16g 32g 64g on
  echo x=1 3 5 7 9
  for %%x IN (9) DO for %%d IN (1024m 768m 512m 384m 256m 192m 128m 96m 64m 48m 32m 24m 16m 12m 8m 6m 4m 3m 2m 1m) DO (
    set "cmd=7z.exe a teste.resultado\%%xx.ppmd.%%dd.%%ww.%%ss.7z .\teste.original\* -mx=%%x -m0=PPMd:mem=%%d:o=%%w -ms=%%s"
    if !startCount! lss %maxProc% (
      set /a "startCount+=1, nextProc=startCount"
    ) else (
      call :wait
    )
    set cmd!nextProc!=!cmd!
    if defined showOutput echo -------------------------------------------------------------------------------
    echo !time! - proc!nextProc!: starting !cmd!
    2>nul del %lock%!nextProc!
    %= Redirect the lock handle to the lock file. The CMD process will     =%
    %= maintain an exclusive lock on the lock file until the process ends. =%
    start /b "" cmd /c %lockHandle%^>"%lock%!nextProc!" 2^>^&1 !cpu%%N! !cmd!
  )
  set "launch="

:wait
:: Wait for procs to finish in a loop
:: If still launching then return as soon as a proc ends
:: else wait for all procs to finish
  :: redirect stderr to null to suppress any error message if redirection
  :: within the loop fails.
  for /l %%N in (1 1 %startCount%) do (
    %= Redirect an unused file handle to the lock file. If the process is    =%
    %= still running then redirection will fail and the IF body will not run =%
    if not defined endProc%%N if exist "%lock%%%N" (
      %= Made it inside the IF body so the process must have finished =%
      if defined showOutput echo ===============================================================================
      echo !time! - proc%%N: finished !cmd%%N!
      if defined showOutput type "%lock%%%N"
      if defined launch (
        set nextProc=%%N
        exit /b
      )
      set /a "endCount+=1, endProc%%N=1"
    ) 9>>"%lock%%%N"
  ) 2>nul
  if %endCount% lss %startCount% (
    1>nul 2>nul ping /n 2 ::1
    goto :wait
  )

2>nul del %lock%*
if defined showOutput echo ===============================================================================
echo Thats all folks!
4

3 回答 3

29

重定向符号前的数字是要重定向的流号。
默认流为 1,当不存在数字时,因此1>...>...是等价的。

流 1 是标准输入/输出流,2 是标准错误流。

一个命令可以输出到多个流,并且允许将每个流重定向到不同的目的地。

所以简单的说,错误输出2>nul1>nul正常输出都会重定向到nul。所以什么都不会输出。

于 2013-10-25T20:51:17.083 回答
2

我的解释:

1. 2>nul del %lock%!nextProc!
2.     %= Redirect the lock handle to the lock file. The CMD process will     =%
3.     %= maintain an exclusive lock on the lock file until the process ends. =%
4.     start /b "" cmd /c %lockHandle%^>"%lock%!nextProc!" 2^>^&1 !cpu%%N! !cmd!
5.   )
6. set "launch="

第 1 行:删除文件并且不显示错误。与“del /Q”相同。感叹号需要启用延迟扩展来评估任何内容。我会写成: del /Q "%lock%!nextProc!"

第 2 行:一种非常奇怪的评论风格。应该只是用“::”开始每一行

第 3 行:与第 2 行相同

第 4 行:如果没有看到脚本的其余部分,很难分辨。%%N 告诉我这部分在循环块内。^ 字符是必需的,以便 start 命令将特殊字符识别为 cmd 命令字符串的一部分。恕我直言,我认为这里不需要启动命令。我敢打赌“start /B /wait”是“start /b”“cmd /c”的等价物。我会亲自重写此脚本以使其更易于理解。

另外,请参阅 dostips.com

另外: 1>nul 2>nul ping /n 2 ::1 是“ping -n 2 -w 1000 127.1 >nul”的等价物,但愚蠢地难以理解。

另外: %~1 表示获取第一个参数 %1 并修剪引号(如果有)

我可以继续说下去,但你应该自己研究一下。

于 2013-10-25T21:39:24.617 回答
0

the 1>nul and 2>nul make it so no output is displayed.
the ^> in the start are so the > are passed to the start command, not interpreted. the cmd /c starts a new shell that executes the code after the /c and then exits.

于 2013-10-25T21:24:41.677 回答