2

特にバッチファイル/スクリプトに「流暢」な人に比べて、私はバッチファイル/スクリプトが非常に苦手です:)。必要なことを実行するのに役立つ単純な (そして「調整」が容易な) バッチ ファイル/スクリプトの作成について本当に助けてほしいです (以下で説明します)。

写真のディレクトリのディレクトリ構造を変換しようとしています。私はこれらのディレクトリのほとんどを 1 つまたは同様の方法で配置していますが、より便利な別の構造に変換したいと考えています。

私の現在の構造は次のとおりです-

PhotosCollection01\
|-> Img003.jpg
|-> Img004.jpg
|-> Img005.jpg
|-> Img007.jpg
|-> Img010.jpg
|-> ...
|-> Chosen\
    |-> Img005.jpg
    |-> Img010.jpg

バッチ ファイル/スクリプトは、構造を次のように変更する必要があります -

PhotosCollection01\
|-> NewName001.jpg (formerly Img003.jpg)
|-> NewName002.jpg (formerly Img004.jpg)
|-> NewName004.jpg (formerly Img007.jpg)
|-> ...
|-> Chosen\
    |-> NewName003.jpg (formerly Img005.jpg)
    |-> NewName005.jpg (formerly Img010.jpg)

これは、バッチファイル/スクリプトが行ったことです-

1) Names are all "NewName???.jpg" (from 001 and up)
2) No duplication of photos under the "Photos" directory and its sub-dirs
3) The "Chosen" directory holds the same amount of photos as before (these were removed from the "Photos" directory)
4) The numbering order of the "NewName" photos is kept in the same order as the "Img" order (although numbering is reset to start from 000)
5) I would love to be able to have "PhotosCollectionXX", "NewNameXXX" and "Chosen" to be able to consist of spaces in their real names

答えが得られるまでは、スクリプトを自分で学習して記述しようと思います。どんな助けでも大歓迎です!

よろしくお願いします、Eyal

4

4 に答える 4

1
@ECHO OFF
SETLOCAL
SET "relroot=u:\photos collection 01"
SET "oldmask=im age"
SET "newmask=new name"
SET "ext=jpg"
SET "skipped="
::
:: step 1 - ensure no 'newname*.ext' exists in the subtree
::
FOR /f %%i IN (
  'DIR /s/b/a-d "%relroot%\%newmask%*.%ext%" 2^>nul^|FIND /c /v "" '
 ) DO IF NOT %%i==0 ECHO Files matching new mask already exist&GOTO :EOF 
::
:: step 2 - list target files
::
:temploop
SET tempfile=%temp%\Photo%random%
IF EXIST "%tempfile%*" GOTO temploop
:: now have random tempfile name
(
FOR /f "delims=" %%i IN (
  'DIR /s/b/a-d "%relroot%\%oldmask%*.%ext%" '
  ) DO (
  ECHO %%~ni*%%~fi
)
)>"%tempfile%1"
::
:: Now do the rename
::
SET count=1000
SET prev=%newmask%
FOR /f %%i IN ('find /c "*" ^<"%tempfile%1"') DO IF %%i gtr 1000 ECHO %%i files - exceeds capacity&GOTO :eof
FOR /f "delims=*" %%i IN ('SORT "%tempfile%1"') DO (CALL :incren "%%i")
IF DEFINED skipped ECHO some files were NOT renamed&DIR /s/b/a-d "%relroot%\%oldmask%*.%ext%"

DEL "%tempfile%1"
GOTO :eof

:incren
:: repeat?
IF "%prev%"==%1 GOTO :EOF
:: no - process next name found
SET "prev=%~1"
FOR %%n IN (firstname secondname) DO (SET %%n=)
:: scan the tempfile, looking for matches to name found
FOR /f "usebackqtokens=1,2delims=*" %%m IN ("%tempfile%1") DO IF /i "%%m"=="%prev%" (
 IF DEFINED firstname SET skipped=Y&IF NOT DEFINED secondname SET secondname=%%n
 IF NOT DEFINED firstname SET firstname=%%n
)
IF DEFINED secondname SET firstname=%secondname%
ECHO REN "%firstname%" "%newmask%%count:~-3%.%ext%"
SET /a count+=1
GOTO :eof

まあ、結局のところ、それほど難しいことではありません。

あなたの仕様に完全に沿っていません-私はファイルの削除を避けているので、名前が重複しているターゲットの名前を変更しませんでした。

ばかげたファイル名 IMO を処理しようとすることにあまりにも多くの注意が払われています。ファイル名に のような文字を使用している場合!%^)=、まあ - あなたはとても頭がいいので、それを理解します。

したがって、適切なファイル名文字とスペースを想定して、動作します!

最初に、relative root(開始サブディレクトリ) 名、使用するファイルマスク、古いものと新しいもの、および拡張子を設定します。私はこのset "var=string"構文を使用して、目に見えず、混乱を引き起こす可能性のある浮遊端末スペースの適用を回避しました。また、文字列の代入では、「=」の両側のスペースが重要であることに注意してください。

最初のステップは文書化されているとおりです。新しい名前に一致するファイルがすでにツリーにある場合はどうすればよいかわかりません。何もしないでください。(ディレクトリ、サブディレクトリあり、基本形式 (ヘッダーなし)、ディレクトリ名なし)から表示される行をカウントするdir /s/b/a-dと、すべてが順調であれば、約 0 になるはずです。

メソッド showm を使用して一時ファイルを設定するのが好きです。選択したランダムな名前に一致する名前がない場合は、%temp%その名前と任意の付録を使用しても安全です (したがって、必要に応じて多くの一時ファイルを作成できます)。

次のステップは、古い名前のファイルのサブディレクトリを基本形式で再度取得することですが、今回は一時ファイルに出力します。出力されるのは、各ファイルの行で、NAME 部分のみ ( %%~ni) アスタリスクと完全なファイル名 ( %%~fi) で構成されています。*アスタリスクは列区切り記号として機能し、ファイル名には使用できないため安全です。

次は名前変更フェーズです。COUNT最後の 3 文字を使用して名前を作成できるように、 を 1000 から開始します。001 から開始したい場合は、代わりに 1001 を使用してください。PREV名前を変更するファイル名として表示できない値に初期化されます。

ここでも、名前を変更する名前を数えます。多すぎる場合は、船を放棄してください。

次のステップは一時ファイルをソートすることです。結果は元のベースファイル名 (各行の「*」の前) の順序で処理され、名前が一致する場合はサブディレクトリ名のアルファベット順 (name* から) で処理されます。親は name*parent\subdir の前にソートされます)。次に、検出された各 NAME がルーチンに渡され:increnます - ファイル名のスペース要件に対応するために引用符が付けられます。

INCREN ルーチンが最初に行うことは、名前が以前に検出された名前を繰り返すかどうかを確認することです。存在する場合、その名前は無視されます (既に処理されているため)。PREV次に見つかった名前に設定されます。SET "prev=%~1"最初のパラメーターから引用符を削除し、結果をに割り当て、引用符を囲んで、迷子のスペースが突き当たるのをprev防ぎます。その後、[nothing] に設定されます。firstnamesecondname

次に、一時ファイルを再度スキャンし、一致する名前を最初のトークンとして探し、2 番目のトークン (完全なファイル名) を%%n

最初のファイル名が見つかった場合、firstname は設定されていないため、完全なファイル名に設定します。2 番目の名前が見つかった場合は、firstname既に設定されSKIPPEDているため、問題が発生したことを示すフラグを設定します。2 番目のファイル名がまだ設定されていない場合は、そのフル ファイル名に設定secondnameします。secondname

ファイルを処理した後firstname、最初の完全なファイル名に設定され (相対ルートが最初に検出されるため)、 secondname2 つ以上の一致する名前が見つかった場合にのみ設定されます。その場合、firstname2 番目に見つかった名前の値に設定します。これは、下位のサブディレクトリになります。

RENAMEを実行します。編集したばかりですが、アクティブにするには、行からECHOを削除します。名前を変更するファイルの完全な名前が含まれていることがわかり、新しいファイル名の構造が新しいマスク +ドットの最後の 3 文字 + 選択した拡張子になることがわかっています。ECHOECHO REN...firstnameCOUNT

次の名前変更に備えてカウントを増やします...

ECHOを削除したテスト実行は次のとおりです。

============= before =========

u:\photos collection 01\im age 612.jpg
u:\photos collection 01\im age 003.jpg
u:\photos collection 01\im age 005.jpg
u:\photos collection 01\im age 610.jpg
u:\photos collection 01\im age 009.jpg
u:\photos collection 01\im age 609.jpg
u:\photos collection 01\im age 505.jpg
u:\photos collection 01\selection 01\im age 001.jpg
u:\photos collection 01\selection 01\im age 004.jpg
u:\photos collection 01\selection 01\im age 005.jpg
u:\photos collection 01\selection 01\im age 006.jpg

=============  run  =========

some files were NOT renamed
u:\photos collection 01\im age 005.jpg

============= after  =========

u:\photos collection 01\new name009.jpg
u:\photos collection 01\new name001.jpg
u:\photos collection 01\im age 005.jpg
u:\photos collection 01\new name008.jpg
u:\photos collection 01\new name005.jpg
u:\photos collection 01\new name007.jpg
u:\photos collection 01\new name006.jpg
u:\photos collection 01\selection 01\new name000.jpg
u:\photos collection 01\selection 01\new name002.jpg
u:\photos collection 01\selection 01\new name003.jpg
u:\photos collection 01\selection 01\new name004.jpg

これは FAT ドライブに対して実行されたので、実際のファイルのシーケンスは 2 つのリストで同じであることに注意してください。

于 2013-04-14T10:07:25.290 に答える
0

出力に問題がなければ、これを試してechobeforeを削除してください:move

@echo off&setlocal
set "sourcefolder=PhotosCollection01"

for /r "%sourcefolder%" %%i in (*.jpg) do (
    if defined "$n%%~nxi" set "$d%%~nxi=%%~nxi"
    set "$p%%~nxi=%%~dpi"
    set "$n%%~nxi=%%~nxi"
)
set "$d" >nul 2>&1 && (
    echo(Duplicate filename(s^):
    for /f "tokens=2delims==" %%i in ('set $d') do echo(%%i
    goto:eof
)
set /a counter=1000
for /f "tokens=2delims==" %%i in ('set $n') do (
    set /a counter+=1
    setlocal enabledelayedexpansion
    if exist "!$p%%~i!NewName!counter:~-3!%%~xi" (
    echo(file already exists: "!$p%%~i!NewName!counter:~-3!%%~xi"
    ) else echo move "!$p%%~i!%%~i" "!$p%%~i!NewName!counter:~-3!%%~xi"
    endlocal
)

サブフォルダーで重複したファイル名が見つかった場合、スクリプトは終了します。targetfile が既に存在する場合、上書きされません。注意: %sourcefolder% 内のすべてのフォルダーは同じカウンターを使用します。異なる選択肢がある場合は、それぞれに対してこのスクリプトを呼び出すか、コメントを書き込んでください。

于 2013-04-14T15:07:33.980 に答える