【问题标题】:How to pipe the final result of a windows batch for loop into another command如何将 Windows 批处理 for 循环的最终结果通过管道传输到另一个命令中
【发布时间】:2018-03-13 03:22:01
【问题描述】:

将我的脚本拆分为两个批处理文件,因为我不知道如何组合它:

简短,让你有一个想法:

1.bat :使用 args 调用 2.bat,对其输出进行排序并使行唯一

FOR /F ... (2.bat %1 ^| sort) DO (...)

do 部分将行相互比较,并使用 linebuffer 排除相同的行

2.bat :作为 FOR 循环的结果打印字符串

FOR ... DO ECHO

在 bash 中这可能看起来像这样:(管道很容易)

(command) | while read line ; do echo $line ; done | sort | uniq

我真的不知道如何在 Windows 批处理中处理 FOR 循环的最终输出以将其结果用于另一个循环(不使用临时文件进行结果缓冲)

这是应用了 jeb 解决方案的整个代码:

@echo off
setlocal EnableDelayedExpansion

REM *** This "goto" to a label, if there is one embedded in %~0 -
FOR /F "delims=: tokens=3" %%L in ("%~0") do goto :%%L

REM *** The second part calls this batch file, but embedd a label to be called
FOR /F "usebackq" %%A IN (`echo dummy ^| call %~d0\:main:\..\%~pnx0 %1 ^| SORT`) DO (
    IF NOT "%%A"=="!buff!" SET str=!str!%%A
    SET buff=%%A
)
ECHO %str:.dll=;%
endlocal
GOTO :eof

REM *** This function will be called in the pipe, but runs in batch context
:main
CD %1
:sub
FOR %%A IN (*.dll *.exe) DO dumpbin /DEPENDENTS %%A | FINDSTR /I "DLL" | FINDSTR /V "Dump :"
FOR /D %%B IN (*) DO (
    CD %%B
    CALL :sub
    CD..
)
GOTO :eof

它返回一行,其中包含 文件夹 [arg1] 及其所有子文件夹中所有文件的运行时依赖项:输出字符串的 .dll 部分被剥离为适合我的需要

ADVAPI32;COMCTL32;COMDLG32;GDI32;KERNEL32;ole32;SHELL32;USER32;WININET;

这是 osx 上使用 pev 工具的对应物:

#!/bin/sh
find "${1}" -type f \( -iname "*.dll" -o -iname "*.exe" \) | while read pe ; do
    readpe -i "${pe}" | grep -i '.dll' | awk '{print $2}'
done | sort | uniq | sed 's/.[dD][lL][lL]//g;' | tr '\n' ';' ## have the BSD sed release and can't use I with sed

【问题讨论】:

    标签: windows batch-file for-loop


    【解决方案1】:

    第一步很简单

    command | (
        for /f "delims=" %%L in ('more') DO @(
           echo # %%L
        )
    ) | sort
    

    但是当你真的想要制作不仅仅是一个简单的回声时,它会变得很糟糕。
    下一个代码将在IF 1 NEQ 2 处失败

    echo dummy | (
        for /f "delims=" %%L in ('more') DO @(
            echo # %%L
            if 1 NEQ 2 echo Not Equal
        ) 
    )
    

    这有不同(复杂)的原因,您可以阅读Why does delayed expansion fail when inside a piped block of code?What happens with IF command when I pipe to it?

    为了能够毫无问题地使用循环,您可以使用调用函数包装器。

    @echo off
    REM *** This "goto" to a label, if there is one embedded in %~0 -
    FOR /F "delims=: tokens=3" %%L in ("%~0") do goto :%%L
    
    REM *** The second part calls this batch file, but embedd a label to be called
    echo dummy | call %~d0\:myFunc:\..\%~pnx0 | sort
    exit /b 
    
    REM *** This function will be called in the pipe, but runs in batch context
    :myFunc
    for /f "delims=" %%L in ('more') DO @(
        echo # %%L
        if 1 NEQ 2 echo Not Equal
    ) 
    exit /b
    

    自调用的工作原理:

    call %~d0\:myFunc:\..\%~pnx0
    

    这将扩展为批处理的完整路径,假设批处理是C:\temp\myFile.bat,那么结果将是:
    call C:\:myFunc:\..\temp\myFile.bat
    这很奇怪,但仍然是有效的路径,因为 :myFunc: 不会被评估,因为 \..\ 部分将删除前一部分。
    所以批处理文件调用自己。

    诀窍在于,:myFunc: 仍然是 %0 变量的一部分。

    FOR /F "delims=: tokens=3" %%L in ("%~0") do goto :%%L
    这部分将%0 by : 拆分为
    "C", "\", "myFunc" and "\..\temp\myFile.bat"
    并将第三个令牌 (myFunc) 用于goto %%L

    这种技术的优点是,它不会破坏现有的批处理文件及其参数处理。
    您也可以将该函数放入%1,但很难猜测该批处理是使用%1 作为转到目标还是将其用作普通参数。

    【讨论】:

    • 我尝试回显您的示例代码的%~d0\:myFunc:\..\%~pnx0 部分,但无法理解。我到处寻找,我能找到的唯一信息显示如何调用第二个批处理文件或如何调用当前批处理文件中的函数。如果我正确理解了您的代码 cmets,那么您似乎都在调用文件(当前文件的新实例)和其中一个函数在同一行代码中。请您更详细地告诉我这是如何工作的?
    • @ChrisD 我添加了How the self-calling works:,希望它能回答你的问题
    猜你喜欢
    • 2011-01-04
    • 1970-01-01
    • 2013-03-12
    • 1970-01-01
    • 2018-01-25
    • 2018-11-17
    • 1970-01-01
    • 2012-08-08
    相关资源
    最近更新 更多