ファイル名の一部を置き換えるようなリネームの方法

今回もYahoo!知恵袋からの質問

コマンドプロンプトを使ったファイルの置換について kmshtkmさん

コマンドプロンプトのrenameで

aaa_bbb.mp3
ccc_ddd.mp3
といったファイル名を

aaa(bbb).mp3
ccc(ddd).mp3
というファイル名に置換したいのですが、どのようにすればいいでしょうか?

rename *_*.mp3 *(*).mp3
としたのですが、ダメでした

http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1121701811

質問は、"_"(アンダーバー)で区切られた前半_後半.mp3 というファイル名の前後を前半(後半).mp3 にリネームしたいという要望と理解しました。例では前半も後半も3文字分ですが長さは不定だとします。

for分の"delims=_"で区切って……と考えましたが、面倒なのでものぐさな方法で作ってみました。
制限事項としてアンダーバーはファイル名に1つあり、前半と後半に区切る場所にある(先頭や末尾にはない)とします。

作ったバッチファイルがこれ。

echo off
for %%a in (*_*.mp3) do call :sub "%%a"
exit /b

:sub
set fname=%~1
set fname=%fname:_=(%
set fname=%fname:.=).%
ren %1 "%fname%"
goto :EOF

単純にファイル名を環境変数に取得して、"_"を"("に、"."を")."に置換して、renameコマンドに渡しているだけです。

DOSバッチで、末尾から特定の文字を検索し、先頭からその文字までを抽出したい。

Yahoo知恵袋での質問。やはりYahooのIDがないのでこちらで勝手に回答します:-P


http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1421612734

DOSバッチで、末尾から特定の文字を検索し、先頭からその文字までを抽出したい。mpmyp813さん

DOSバッチで、末尾から特定の文字を検索し、先頭からその文字までを抽出したい。

テキストファイルの各行末尾から特定の文字を検索し、見つかった場所から末尾までを削除した行を他のテキストファイルの出力したいのですが、うまくできません。
下記のようなファイルから、各行の末尾から”}”までを除いた文字列を別ファイルresult.txtに出力したいです。


---検索対象ファイル:input.txt---
abc{12345}{de}abcdefg
ljklm{6789}{nop}vwxyz
-------------------------

---抽出後イメージ:result.txt---
abc{12345}{de}
ijklm{6789}{nop}
-------------------------

アルファベット部分および数字表記の文字数は可変なので”x文字目からy文字”という指定はできません。
また、先頭から複数個の”}”が存在するので、先頭からx”}”という検索ができないと思っています。
そのため、"}"が末尾から何文字目に出現するかを変数Sに入れ、”行の先頭からS文字目まで”というイメージになるのですが、どのように書いたらいいでしょうか?

エクセルの関数では以下のような式で実現できます。

セルA1(対象文字列): abc{12345}{de}fgh999uvw
セルB1(抽出関数): =LEFT(A1,LEN(A1)-LEN(RIGHT(A1,FIND("}",A1)-1)))


説明不足でしたら補足いたします。
よろしくお願い致します。

http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1421612734

質問されているmpmyp813さんは

そのため、"}"が末尾から何文字目に出現するかを変数Sに入れ、”行の先頭からS文字目まで”というイメージになるのですが、どのように書いたらいいでしょうか?

と書かれているますが、バッチには検索文字列の位置を返すようなVBのindex関数やexcelのfind関数のようなコマンドは見あたらないので、別の方法を考えるしかないと考えました。

まず抽出前と抽出後のイメージを見比べてみて、}を区切りとして文字列を分けることを考えます。そうすると、for /F "delims=}"が真っ先に思い付くのですが、区切られるtokenの数が固定の場合はこれでいいのだけれども、今回は数が不定("}"の数が固定と書かれていない)ためこの方法は使わないことにします。(質問で示されている例を見る限りはxxxx{yyyy}{zzz}ddddの4ブロック固定でddddの部分を削除すればいいようにも取れますが)

そこでまず、for /F "delims=" で1行分をそのままサブルーチンに渡すことにしました。

for /F "delims=" %%l in (input.txt) do call :sub "%%l"

受け取ったサブルーチンでは一旦環境変数lineに全てを入れて、環境変数の置換(set /?を参照のこと)使って、"}"を空白に置換したものを2つめのサブルーチンの引数にして呼び出します。

2つめのサブルーチンでは、"}"で区切られた引数がそれぞれ %1 %2 %3 ... に入ることになります。そしてこの引数の一番最後が今回削除したい文字列になるわけです。

あとは、2つめのサブルーチンで %1 の引数が空になるまで、shift コマンドを使って引数をシフトしながらループします。その際 %1 の内容を一時的に環境変数xに待避しておきます。こうすることで、%1が空になったとき、直前の引数が環境変数xに残るわけです。
今回の例だと環境変数xにはabcdefgが入ります。

:sub2
  if "%1"=="" goto exit_loop
  set x=%1
  shift
goto sub2
:exit_loop

最後の仕上げは、1行の文字列(環境変数line)から削除したい文字列(環境変数x)を削除するところです。これは先ほども使った環境変数の置換を使います。

call set ans=%%line:%x%=%%

この call set 〜 というのが一時的な遅延展開をしているところで、まず call set ans=%%line:%x%=%% という行がバッチファイルとして実行されると、%%→% と %x% の環境変数の展開が行われます。

call set ans=%line:abcdefg=%

ここでcall文が実行され、set ans=%line:abcdefg=% が子プロセスのようにして実行されるようです(call /? ではcall :ラベルで「指定された引数で新しいバッチ ファイル コンテキストが作成され」と書いてありますが内部コマンドでも同じのようです)。
環境変数グローバル変数のように扱われますから、環境変数ansの内容はcall文実行後も保持されてめでたくabcdefgを空に置換(=削除)してくれた結果が環境変数ansに入ります。
最後に結果をresult.txtに出力して終わり。

ということで最終的にできたバッチはこれです。

:----------------------------------------------------- sample.bat
echo off
for /F "delims=" %%l in (input.txt) do call :sub "%%l"
type result.txt
exit /b

:sub
set line=%~1
call :sub2 %line:}= %
goto :EOF

:sub2
  if "%1"=="" goto exit_loop
  set x=%1
  shift
goto sub2
:exit_loop
call set ans=%%line:%x%=%%
echo %ans%>>result.txt
goto :EOF

このページ見てくれればいいんですが、やっぱり無理かなぁ。

ファイルの名前の前に、親フォルダの名称を自動的に付ける

OKWave からフリーソフトを探していますという相談。これをバッチで実現してみます。
http://okwave.jp/qa4545395.html

質問者:rack-an ファイルの名前の前に、親フォルダの名称を自動的に付けるフリーソフト

親フォルダの名前を、そのフォルダ内の各ファイルに自動で追加リネームできるフリーソフトを探しています。ご存じの方がいらっしゃいましたらお願いします。

例:
【変換前】
<親フォルダ>   <ファイル群>
ABCD-4567-XY  ┬  01_photo.jpg
        ├  02_photo.jpg
        └  03_photo.jpg

【変換後】
<親フォルダ>   <ファイル群>
ABCD-4567-XY  ┬  ABCD-4567-XY_01_photo.jpg
        ├  ABCD-4567-XY_02_photo.jpg
        └  ABCD-4567-XY_03_photo.jpg

何卒よろしくお願いします。

http://okwave.jp/qa4545395.html

引数に該当するフォルダや該当するフォルダ内の1ファイルを指定するとします。
この方が便利だと思ったのだが、これが意外と手こずる原因になってしまいました。
素直に引数にはフォルダを指定するだけならもう少し簡単になっていたと思います。
dir /a:d 云々のところが引数がフォルダ指定なのかファイル指定なのかを判断している所です。ファイルを指定して場合は、一旦ファイルのディレクトリに移動して、%CD%でディレクトリのフルパスを取得して自分自身を呼び出しています。なんでこんなまどろっこしい事をしているかというと、%~dp1では最後に"\"が付いてしまうためこれを取り除くための苦肉の策です。

環境変数pnameには指定したフォルダのパスが、環境変数nameにはフォルダ名が入ります。
あとは、for文でフォルダ内のファイルに対して、リネームを行います。

"%%f"にはファイルのフルパスが入ります。
"%name%_%%~nxf" で"フォルダ名_ファイル名(拡張子付き)"となります。

for文の in ("%pname%"\*) → in ("%pname%"\*.jpg) 等とすると拡張子がjpgのファイルのみリネームするようなことも可能です。

echo off
:--------------------------------------------------- sample.bat
if "%~1"=="" goto usage
  dir /a:d "%~1">NUL 2>&1
  if %errorlevel% EQU 0 goto top
:    ファイルを指定した場合
     pushd "%~dp1"
     "%~f0" "%CD%"

:パスとフォルダ名を取得
:top
set pname=%~f1
set name=%~nx1

for /f "delims=" %%f in ('dir /b "%pname%"') do ren "%pname%\%%f" "%name%_%%f"

goto :EOF

:usage
echo usage: %0 folder or file
echo リネームしたいファイルの入っているフォルダや該当するフォルダ内の1ファイルを指定します。

Yahoo知恵袋 batファイルの作り方を教えてください。(『新しいフォルダ』の中に『0kb』のファイルがあればそれは削除する。)

Yahoo知恵袋にあった質問

batファイルの作り方を教えてください。xpmyg273さん

batファイルの作り方を教えてください。

・デスクトップ上に『新しいフォルダ』という名前のフォルダが存在します。

・そのフォルダの中には
(1)あいうえお.dat(25kb)
(2)かきくけこ.dat(0kb)
という2つのファイルがあります。

ここでこういうBATファイルを作成したいのです。

『新しいフォルダ』の中に『0kb』のファイルがあればそれは削除する。』

こういった命令のBATファイルは作成可能でしょうか?

http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1221136007

※(1),(2)は丸数字

デスクトップ上に「新しいフォルダ」という名前のフォルダあって、その中のファイルサイズが0のファイルを(名前に関係なくすべて)削除するという質問と認識しました。

まずデスクトップですが、"%USERPROFILE%\デスクトップ" で表現できます。デスクトップ上の「新しいフォルダ」なら "%USERPROFILE%\デスクトップ\新しいフォルダ"となります。

ファイルサイズを調べる簡単な方法は for文のファイルセットに対して、for変数の置換を使う方法です。詳しくは for /? で。for文の変数を %%f とすると、%%~zfがファイルサイズに置き換わります。

作ったサンプルはこちら。(一応 .dat のファイルのみ対象にしています。)

echo off
for %%f in ("%USERPROFILE%\デスクトップ\新しいフォルダ\*.dat") do if %%~zf EQU 0 del "%%f"

これでファイルサイズが0の拡張子がdatのファイルを削除します。
*.dat → *
にすると新しいフォルダ内の全ファイルを対象にします。

USBメモリ内のフォルダ名をログインユーザ名に書き換える

Sleipnirの旧バージョンをUSBメモリに入れている人の質問。

質問者:office1412 USBメモリ内のフォルダ名をログインユーザ名に書き換える
困り度:すぐに回答を!

USBメモリにあるフォルダ名をログインユーザ名に書き換えるバッチファイルの作成に困っております。
現在、仕事でSleipnir1.66をUSBメモリに入れて持ち歩き、出先のPCと会社のPC、そして自宅のPCと三箇所でそのブラウザを使う事があります。
問題なのは、「USBメモリのドライブ:\Sleipnir\user\USERNAME」のドライブ名とUSERNAME部分です。
Sleipnirの環境設定がログインユーザ名ごとにフォルダが作成されそこに保存されるので、USBメモリを挿すPCが変わると当然ながらユーザ名が変わってしまいます。
今までは、手動でユーザ名を調べてそのユーザ名に書き換えていましたが、それをBATファイルで自動化できないかと考えました。

ですが、DOSが良く分かりません。
接続するPCによっては、USBメモリのドライブも変わりますし、ユーザ名を%USERNAME%で参照できるらしい事、RENでフォルダ名を変えられる事、など断片的に情報は集まりましたが、どのように処理を書けば良いのか分かりません。
やりたい事を以下に記します。(BATファイルはUSBメモリ内にあるとして)

1.USBメモリのドライブを調べる
2.ログインユーザ名を調べる
3.「1」で調べた結果:\Sleipnir\user\「2」で調べたユーザ名 に書き換えたい。

かましいとは思いますが、どなたか希望に沿うBATファイルを作成して頂けませんでしょうか。

http://okwave.jp/qa4513495.html

とりあえず、やりたい事に書いてある条件を満たすバッチを作成した。
USBメモリのドライブを調べるというのは一瞬厄介かなと思ったが、今回はUSBメモリにバッチを置いて一緒に持ち歩くということなのでバッチのカレントドライブを取得できれば良い。従って %~d0 で得られる。

たとえばバッチがE:\sample\sample.batだったとするとそのバッチ内では、

%~d0 E:
%~dp0 E:\sample\
%~f0 E:\sample\sample.bat

となる。このあたりの~d とか ~dp とかの解説は call /? と入力すると出てくるヘルプの後半に書いてある。
%0がそのバッチファイル自身を差すことはどこに書いてあるんだっけ?
ヘルプを探してみたら、ここで少しだけ触れられている → ms-its:C:\WINDOWS\Help\ntcmds.chm::/percent.htm


それより、ディレクトリ(フォルダ)名もrename (ren)コマンドで変更出来るというのを改めて認識。なぜかmoveを使うモノだと思いこんでいた。

で、作ったサンプルがこれ。

:----------------------------------chguser.bat
echo off
for /D %%d in (%~d0\Sleipnir\user\*) do ren %%d %USERNAME%
start %~d0\Sleipnir\Sleipnir.exe

Sleipnir1.66を持っていないので実際にSleipnirが立ち上がるところまでは確認していないけどいいか。

教えて!gooの検索が復活

先日のエントリーで書いた教えて!goo の検索がおかしい件ですが、RSSリーダに登録していたバッチファイル関係の質問の検索結果のRSSが最新の日付で表示されるようになりました。
復活したようで一安心です。

Re:Re:here:「ここにあとで来る」ためのバッチファイルを作るスクリプト

id:fumokmm さんの以下のエントリーのバッチファイル版を作ってみた。

Re:here:「ここにあとで来る」ためのバッチファイルを作るスクリプト

echo off
set HERE_BATCH="%~dp0"

if "%1"=="" (
   for %%f in ( %HERE_BATCH%*.bat ) do if /I not %%~nxf==here.bat echo %%~nf
   for %%f in ( %HERE_BATCH%*.bat ) do if /I not %%~nxf==here.bat exit /b
   echo Usage: here project-code 
   echo Example: here proj
) else (
   if "%1"=="here" pushd %HERE_BATCH% & exit /b
   echo echo off>%HERE_BATCH%%1.bat
   echo pushd %CD%>>%HERE_BATCH%%1.bat
)

正直 groovyという処理系はここで初めて知った。なんとなく読める内容なので推測してバッチファイルで書いてみたが、若干ニュアンスが違っているかもしれない。here hereとやっちゃうと自分自身を書き換えてしまうので、here hereとした場合は here.bat のある場所に移動することにした。

here.bat と同じディレクトリに「あとで来るバッチ」を作るので、here.batをどこか独立したディレクトリにいれてPATHを切っておくのが良いと思われる。

ご紹介した id:fumokmm さんのエントリーの元ネタは、2006-06-01 だそうです。