Reputation: 33
have my script splitted into two batch files as i dont know how to combine it:
short so you get an idea:
1.bat : calls 2.bat with args, sorts its output and makes lines unique
FOR /F ... (2.bat %1 ^| sort) DO (...)
the do part compares lines to each other and excludes identical lines using a linebuffer
2.bat : prints strings as a result of an FOR loop
FOR ... DO ECHO
in bash this might look like this: (piping is easy)
(command) | while read line ; do echo $line ; done | sort | uniq
i really dont know how to process the final output of a FOR loop in windows batch to use its result with another loop (without using temp files for result buffering)
This is the whole code with jeb's solution applied:
@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
it returns a single line with runtime dependencies of all files inside a folder [arg1] and all its subfolders : the .dll part of the output string is stripped to suit my needs
ADVAPI32;COMCTL32;COMDLG32;GDI32;KERNEL32;ole32;SHELL32;USER32;WININET;
here is the counterpart on osx using pev tools:
#!/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
Upvotes: 2
Views: 2022
Reputation: 82307
The first step is simple
command | (
for /f "delims=" %%L in ('more') DO @(
echo # %%L
)
) | sort
But it's get nasty when you really want to make more than a simple echo.
The next code will fail at the IF 1 NEQ 2
echo dummy | (
for /f "delims=" %%L in ('more') DO @(
echo # %%L
if 1 NEQ 2 echo Not Equal
)
)
This has different (complex) reasons, you can read at Why does delayed expansion fail when inside a piped block of code? and What happens with IF command when I pipe to it?
To be able to use the loop without problems you can use a call-function-wrapper.
@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
How the self-calling works:
call %~d0\:myFunc:\..\%~pnx0
This expands to the full path of the batch, assuming the batch is C:\temp\myFile.bat
then the result will be:
call C:\:myFunc:\..\temp\myFile.bat
This is strange but still a valid path, because :myFunc:
will not be evaluated as the \..\
part will remove the previous part.
So the batch file calls itself.
The trick is, that :myFunc:
is still part of the %0 variable.
FOR /F "delims=: tokens=3" %%L in ("%~0") do goto :%%L
This part splits the %0
by :
into
"C", "\", "myFunc" and "\..\temp\myFile.bat"
And the use the third token (myFunc
) for the goto %%L
.
The advantage of this technic is, it doesn't break existing batch files and their parameter handling.
You could put the function also into %1
but then it's hard to guess if the batch shall use %1
as a goto destination or use it as a normal parameter.
Upvotes: 5