kasimodo
Goto Top

Batch mit For Schleife - gestaffelt nach Anzahl von Files in einem Verzeichnis

Ein freundliches "Hallo" und mein erster Dank für das Lesen meiner Frage!
von Kasimodo

Mit dem Tool PDFTK möchte ich viele PDF zusammenführen (merge)!

Syntax beispiel:
pdftk 1.pdf 2.pdf 3.pdf cat output neu_Seitenzahl.pdf
or (Using Wildcards):
pdftk *.pdf cat output neu_seitenzahl.pdf

Ausgangssituation:

Im Verzeichnis ist eine unbekannte Anzahl von PDFs. (von 1 bis ?) Alle haben einen willkürlichen Dateiname.
Sortiert nach Erstellung (Datum/Zeit) sollen immer 20 PDFs zu einer zusammengefasst werden, eine laufende Nummer und die Anzahl der Seiten sollen an die neue PDFdateinamen angefügt werden.

Beispiel 1:
106 PDFs im Verzeichnis C:\A sollen zusammengefasst werden zu 5 Dateien zu je 20 und einer mit 6.
A_1_020.pdf
A_2_020.pdf
A_3_020.pdf
A_4_020.pdf
A_5_020.pdf
A_6_006.pdf

Beispiel 2:
18 PDFs im Verzeichnis C:\A soll zu A_018.pdf werden.

Wie kann man diese 20er Schleife und den Rest (weniger als 20) realisieren?

Danke für jegliche Hilfe!

kasimodo

Content-Key: 118892

Url: https://administrator.de/contentid/118892

Printed on: April 25, 2024 at 15:04 o'clock

Mitglied: 77559
77559 Jun 24, 2009 at 09:55:31 (UTC)
Goto Top
Hallo Kasimodo,

leider schreibst du nicht in welcher Umgebung das laufen soll.
Das könnte der Beschreibung nach genauso Linux wie Windows sein.

Weil mich das Thema der Gruppierung interessierte, habe ich mal eine Batch geschrieben die sich auch zum zusammen Kopieren von Textdateien eignen würde.

In deinem Text gehst du wie selbstverständlich davon aus das eine pdf Datei nur eine Seite hat, was aber nur in deinem konkreten Fall so sein dürfte.
Ich habe möglichst sprechende Variablennamen verwendet, speche aber von Files nicht Seiten.

:: MergeFilesGroup.cmd :::::::::::::::::::::::::::::::::::::::::::::::
@Echo off&SetLocal
Set Base=D:\Test\
Set Ext=cmd
Set FilesPerGroup=5
Set Prefix=A
:: ^^^^^ Variablen oberhalb anpassen.
Pushd "%Base%"  
For /F %%A in ('Dir /B /A-D /OD "*.%Ext%"^|Find /V /C "" ') Do Set FileCnt=%%A  
Set /A "FullGroupCnt=FileCnt/FilesPerGroup,LastGroupFilesCnt=FileCnt %% FilesPerGroup+1000"  
For /F "tokens=1,* Delims=:" %%A in (  
  'Dir /B /A-D /OD "*.%Ext%"^|Findstr /N $'  
    ) Do Call :BuildGroups %%A "%%B"  
Set /A "FilesPerGroup+=1000"  
Set FilesPerGroup=%FilesPerGroup:~-3%
For /F "tokens=2,* delims=_=" %%A in (  
  'set Group_') Do Set /A "GroupNum=%%A-1000"&Call :Process %%B  
popd
Pause
Goto :Eof

:BuildGroups
Set /A "GroupNum=(%1-1) / FilesPerGroup +1001"  
Call Set Group_%GroupNum%=%%Group_%GroupNum%%% %2
Goto :Eof

:Process
If %GroupNum% LEQ %FullGroupCnt% (
  Set GroupName=%Prefix%_%GroupNum%_%FilesPerGroup%.%Ext%
) Else (
  Set GroupName=%Prefix%_%GroupNum%_%LastGroupFilesCnt:~-3%.%Ext%
)
Echo pdftk %* cat output %GroupName%

Wenn nach Anpassung der Variablen die Ausgabe korrekt erscheint, kann das Echo in der letzten Zeile und die Pause in Zeile 19 entfernt werden.

Gruß
LotPings
Member: kasimodo
kasimodo Jun 24, 2009 at 19:50:18 (UTC)
Goto Top
Danke LotPings !!

Stchwort "Gruppierung" - genau das war der Punkt an dem ich nicht weiter kam.

Klasse deine Lösung für Windows face-wink

Die Gruppierung ist ein kleiner aber wichtiger Teil in der von mir geplanten "großen" Batch. Dank deiner Hilfe kann es nun damit weiter gehen.

Danke und Gruß
Kasimodo
Member: kasimodo
kasimodo Jun 26, 2009 at 23:08:23 (UTC)
Goto Top
Hallo!

Nun geht das Gruppieren auch über SubFolder! face-smile

Nur eine kleine Frage bleibt:
Wie kann ich die Anzahl der Zeichen von der Variable "Base" ermitteln und diese Anzahl einer neuen Variable zuweisen?
Dann könnte ich den Wert der neuen Variable für Set "FILE_PATH=!FILE_PATH:~10!" benutzen! Die "10" soll durch variable ersetzt werden! (siehe im Code unten - zwischen den vielen !!!!!)

Danke & Gruß
kasimodo

rem Gruppieren & Packen & Umbenennen
@echo off & setlocal EnableDelayedExpansion
cls

rem ------ Variable setzen ---------
Set "Base=D:\ABC_READ"  
set "Ausgabe=D:\ABC_Fertig"  
Set "Ext=pdf"  
Set "FilesPerGroup=20"  
rem ------ Variable setzen Ende---------

Pushd "%Base%"  
Rem run for all SubFolders
For /f %%i in ('dir /B /AD /S /ON') do (  
cd %%i
Set "FILE_PATH=%%~pni"  
Set "FILE_PATH=!FILE_PATH:\=_!"  

rem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
rem Anpassen in Abhaenigkeit Laenge vom "Base" (benoetig fuer Name 'sOutputfile')  
rem Anzahl von Zeichen in "Base"-1  
Set "FILE_PATH=!FILE_PATH:~10!"  
rem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

rem ----------- Gruppierung ------------
For /F %%A in ('Dir /B /A-D /OD "*.%Ext%"^|Find /V /C ""') Do Set FileCnt=%%A  
IF NOT !FileCnt!==0 (
Set /A "FullGroupCnt=FileCnt/FilesPerGroup"  
Set /A "LastGroupFilesCnt=FileCnt - FullGroupCnt * FilesPerGroup"  
For /F "tokens=1,* Delims=:" %%A in ('Dir /B /A-D /OD "*.%Ext%"^|Findstr /N $') Do Call :BuildGroups %%A "%%B"  
rem --------------------------------------
For /F "tokens=2,* delims=_=" %%A in ('set Group_') Do Set /A "GroupNum=%%A"&Call :Process %%B  
For /F "tokens=1,* delims==" %%k in ('set Group_') Do Set %%k=  
)
)
Popd
pause
Goto :Eof

rem ====== SUB Begin =========
rem--------- Gruppe erstellen------
:BuildGroups
Set /A GroupNum=(%1-1) / %FilesPerGroup% +1001
Call Set Group_%GroupNum%=%%Group_%GroupNum%%% %2
Goto :Eof
rem--------- Gruppe Ende------

:Process
rem mache etwas damit
echo !FILE_PATH!
echo %GroupNum%
echo  %*
Goto :Eof
rem ======= SUB END =========
Mitglied: 77559
77559 Jun 27, 2009 at 08:21:08 (UTC)
Goto Top
Hallo kasimofo,

Wenn du zwischendurch CD benutzt, hast du das Konzept von Pushd Popd nicht wirklich verstanden. Siehe Pushd /?

Auch kann man Calls weiter staffeln und dabei auch mit setlocal/endlocal arbeiten um nicht alte Variableninhalte mitzuschleppen. (Das löschen der Group_ Variablen kann somit entfallen) Siehe setlocal /?

Wenn File_Path den relativen Pfad enthalten soll, kannst du einfach Base aus File_Path entfernen mit
set File_Path=!File_Path:%Base%=!

Oder nimm in deiner Zeile 16 gleich statt %~pni besser %~nxi um den Ordner Namen zu erhalten.

Ich habe im Code zwei Zeilen eingebaut um das Debuggen zu erleichtern.
Wenn die Variable Debug auf "::" gesetzt ist werden die Zeilen ignoriert, bei Echo. erhältst du die Ausgabe

Die For Schleife zum ermitteln des fileCnt hat im Dir einen Umleitung der Fehlerausgabe auf NUL erhalten um "Datei naicht gefunden" zu unterdrücken.

rem Gruppieren & Packen & Umbenennen
@echo off & setlocal EnableDelayedExpansion
cls
rem ------ Variable setzen ---------
Set "Base=D:\ABC_READ"  
set "Ausgabe=D:\ABC_Fertig"  
Set "Ext=pdf"  
Set "FilesPerGroup=20"  
Set "Debug=:: "  
:: set Debug=Echo.
rem ------ Variable setzen Ende---------
Set Base=D:\Test
set "Ext=cmd"  
Pushd "%Base%"  
:: run For Base Folder
For %%i in (%CD%) do Call :ProcFold "%%i" "%%~nxi"  
:: run for all SubFolders
For /f %%i in ('dir /B /AD /S /ON') do Call :ProcFold "%%i" "%%~nxi"  
Popd
pause
Goto :Eof

:ProcFold  %1=Kompletter Pfad %2=Name.Erw  ------ Ordner verarbeiten -------
Setlocal
Pushd %1
%Debug% %CD% %1 %2 &Pause
Set "Folder_Name=%~2  
For /F %%A in ('Dir /B /A-D /OD "*.%Ext%"2^>NUL^|Find /V /C "" ') Do Set FileCnt=%%A  
IF 0==%FileCnt% Goto :Exit
Set /A "FullGroupCnt=FileCnt/FilesPerGroup"  
Set /A "LastGroupFilesCnt=FileCnt - FullGroupCnt * FilesPerGroup"  
For /F "tokens=1,* Delims=:" %%A in ('Dir /B /A-D /OD "*.%Ext%"^|Findstr /N $') Do Call :BuildGroup %%A "%%B"  
rem --------------------------------------
For /F "tokens=2,* delims=_=" %%A in ('set Group_') Do Set /A "GroupNum=%%A"&Call :ProcGroup %%B  
:Exit
Popd
:: mit dem Goto :Eof ist ein Endlocal implizit
Goto :Eof

:BuildGroup       --------- Gruppe erstellen ------
Set /A GroupNum=(%1-1) / %FilesPerGroup% +1001
Call Set Group_%GroupNum%=%%Group_%GroupNum%%% %2
%Debug% Call Set Group_%GroupNum%=%%Group_%GroupNum%%% %2
Goto :Eof

:ProcGroup       --------- Gruppe ausgeben ------
rem mache etwas damit
echo CD=%CD% Folder_Name=%Folder_Name% 
echo Gruppe=%GroupNum:~-3%
echo  %*
Goto :Eof

Gruß
LotPings
Member: kasimodo
kasimodo Jun 30, 2009 at 18:37:46 (UTC)
Goto Top
Hallo LotPings,

vielen Dank für die Hinweise und deine Hilfe!!
ich hatte die letzten Tage nicht viel Zeit und konnte erst heute weitermachen. Das Script macht nun alles so wie ich es möchte.

Auch die Namensbildung der Ausgabedatei %"GroupName"% ist nun OK. Habe es etwas anders gemacht als von dir vorgeschlagen. Der Name soll sich aus allen SubVerzeichnisnamen - beginn nach %Base% - zusammensetzen. Der "\" wird durch "_" ersetzt. (Siehe ab "Set "File_Path= " und folgend.) Geht bestimmt auch kürzer - aber es funktioniert! Duch die extra SUB für "GroupName" kann ich schnell auf Veränderungen reagieren.

Danke und Gruß
kasimodo


rem Gruppieren & Packen & Umbenennen
@echo off & setlocal EnableDelayedExpansion
cls
rem ------ Variable setzen ---------
Set "Base=D:\ABC_READ"  
set "Ausgabe=D:\ABC_Fertig"  
Set "Ext=pdf"  
Set "FilesPerGroup=20"  
set GS=D:\Programme\gs\gs8.64\bin\gswin32
Set "Debug=:: "  
:: set Debug=Echo.
rem ------ Variable setzen Ende---------

rem ----- fuer Test------
:: Set Base=D:\Test
:: set "Ext=cmd" 
rem ----- fuer Test ENDE------

Pushd "%Base%"  
:: run For Base Folder --- wird nicht gebraucht ----
rem For %%i in (%CD%) do Call :ProcFold "%%i" "%%~nxi"  

:: run for all SubFolders
For /f %%i in ('dir /B /AD /S /ON') do Call :ProcFold "%%i" "%%~nxi"  
Popd
rem cls
echo.
echo.
echo ------------------------------------------
echo.
echo               FERTIG
echo.
echo ------------------------------------------
echo.
pause
Goto :Eof

:ProcFold  %1=Kompletter Pfad %2=Name.Erw  ------ Ordner verarbeiten -------
Setlocal
Pushd %1
%Debug% %CD% %1 %2 &Pause

Set "File_Path=%CD%"  
Set "File_Path=!File_Path:%Base%=!"  
Set "File_Path=!File_Path:\=_!"  
Set "File_Path=!File_Path:~1!"  

For /F %%A in ('Dir /B /A-D /OD "*.%Ext%"2^>NUL^|Find /V /C "" ') Do Set FileCnt=%%A  
IF 0==%FileCnt% Goto :Exit
Set /A "FullGroupCnt=FileCnt/FilesPerGroup"  
Set /A "LastGroupFilesCnt=FileCnt - FullGroupCnt * FilesPerGroup"  
For /F "tokens=1,* Delims=:" %%A in ('Dir /B /A-D /OD "*.%Ext%"^|Findstr /N $') Do Call :BuildGroup %%A "%%B"  
rem --------------------------------------
For /F "tokens=2,* delims=_=" %%A in ('set Group_') Do Set /A "GroupNum=%%A"&Call :ProcGroup %%B  
:: ----- PDF Quelle Umbenennen nach *.pd_------
rem ren *.%Ext% *.pd_
:Exit
Popd
Goto :Eof

:BuildGroup       --------- Gruppe erstellen ------
Set /A GroupNum=(%1-1) / %FilesPerGroup% +1001
Call Set Group_%GroupNum%=%%Group_%GroupNum%%% %2
%Debug% Call Set Group_%GroupNum%=%%Group_%GroupNum%%% %2
Goto :Eof

:ProcGroup       --------- Gruppe ausgeben ------
Call :BuildName GroupName
echo. ---------------------------
pdftk %* cat output "%Ausgabe%\%GroupName%" dont_ask  
Goto :Eof

:BuildName      ---Regel fuer Name "GroupName" --- 
If %FileCnt% LEQ %FilesPerGroup% (Set "LongGroupNum=_") ELSE (Set "LongGroupNum=__%GroupNum:~-2%")  
Set /A "LongFilesPerGroup=FilesPerGroup + 1000,LongLastGroupFilesCnt=LastGroupFilesCnt + 1000"  
Set LongFilesPerGroup=%LongFilesPerGroup:~-2%
Set LongLastGroupFilesCnt=%LongLastGroupFilesCnt:~-2%
Set /A "GroupNum-=1000"  
If %GroupNum% LEQ %FullGroupCnt% (
	Set Name=!File_Path!%LongGroupNum%_S%LongFilesPerGroup%.%Ext%
) Else (
	Set Name=!File_Path!%LongGroupNum%_S%LongLastGroupFilesCnt%.%Ext%
)
set "%1=%Name%"&goto :eof