質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.40%
Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

コマンド

コマンドとは特定のタスクを行う為に、コンピュータープログラムへ提示する指示文です。多くの場合、コマンドはShellやcmdようなコマンドラインインターフェイスに対する指示文を指します。

コマンドライン

コマンドライン(別名:Command Line Interface)は、ユーザに命令の入力を促す(プロンプト)文字列の表示を行い、すべての操作をキーボードを用いて文字列を打ち込む事でプログラムを走らせるユーザインターフェースです。

バッチファイル

バッチファイル(Batch File)は、Windowsのコマンドラインインタープリターによって複数のコマンドを実行させる事が出来るスクリプトファイルです。

Q&A

解決済

1回答

336閲覧

文字列切り取りから取得した値を使用する方法について

taka0920

総合スコア3

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

コマンド

コマンドとは特定のタスクを行う為に、コンピュータープログラムへ提示する指示文です。多くの場合、コマンドはShellやcmdようなコマンドラインインターフェイスに対する指示文を指します。

コマンドライン

コマンドライン(別名:Command Line Interface)は、ユーザに命令の入力を促す(プロンプト)文字列の表示を行い、すべての操作をキーボードを用いて文字列を打ち込む事でプログラムを走らせるユーザインターフェースです。

バッチファイル

バッチファイル(Batch File)は、Windowsのコマンドラインインタープリターによって複数のコマンドを実行させる事が出来るスクリプトファイルです。

0グッド

1クリップ

投稿2024/07/15 09:21

お世話になっております。
特定のフォルダ内を検索して、下記のような形式のファイル名の一部を切り取り、ファイル名の一部の文字列を含む名前のフォルダの存在チェックをする処理をバッチ処理で作成しようとしています。

使用するファイル名の形式
「0000_11111_22222.pdf」

具体的には以下のようなコードを作成しています。

CMD

1rem 初期化 2set OUTPUT_PATH=D:\TEST 3set HENSU1=0 4set HENSU2=0 5 6for %%a in (*.pdf) do ( 7 8 for /f "delims=_ tokens=1-2" %%A in ("%%a") do ( 9 rem %%Aには「0000」、%%Bには「11111」が取得されている 10 rem ここで%%Aと%%Bが変数に格納されない 11 set HENSU1=%%A 12 set HENSU2=%%B 13 echo 1:%OUTPUT_PATH%\%%B:~0,4% 14 →① 実行結果:D:\TEST\11111:~0,4 … 文字列切り取りができていない 15 echo 2:%OUTPUT_PATH%\%%B:~0,4%\%%A 16 →② 実行結果:D:\TEST\11111:~0,4A … %%Aの値が参照できていない 17 if not exist %OUTPUT_PATH%\%%B:~0,4% ( 18 mkdir %OUTPUT_PATH%\%%B:~0,4% 19 ) 20 ) 21

このように、特定のフォルダ内を検索し、検索対象のファイル名の文字列を「_」で区切り、%%Aと%%B内の文字列を変数に格納して後続の処理で文字列を連結、切り取り等の操作をしたいと考えています。
なのですが、上記を実行してもHENSU1、HENSU2には「0」が格納されていて%%Aと%%Bの文字列が変数に取得されていないようです。

教えていただきたいことは以下です。
・①のように%%B内の値の文字列の切り取りなどの操作はできないのでしょうか。
・②のように%%Aの値が参照できないのはなぜなのでしょうか。
・%%A、%%Bで取得した値を使用するためにはどのようなやり方をすればよいのでしょうか。

お手数をおかけしますが、有識者の方おられましたらご教示ください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

まず、バッチスクリプトの文法は、一般のプログラミング言語の常識が通じない部分があるので、
・バッチスクリプトは簡単なケースだけしか使わない
・じっくりバッチスクリプトの文法を理解して熟練者になる
のどちらの方針で臨むかを最初に決めた方が良いです。

このレベルの処理をするなら、バッチスクリプトの熟練者を目指すのでなければ、他の言語をお勧めします。
・PowerShell
・VBScript (廃止予定なので、5年、10年後に使えなくなってもいい場合)
・OfficeのVBA
・WSL1またはWSL2 の bash等(デフォルトでは未インストールのはずなのでMSからインストール要)
・Windows非標準の各種プログラミング言語(インストール可能なら)
あるいは、後出の「案2」だとバッチスクリプトでもそれほど熟練者じゃなくてもいいかも。そんな気が強くしてきました。

以下、バッチスクリプトでやる場合の説明。
「環境変数」は「変数」とついてますが、一般のプログラミング言語の変数とは少し違います。

上記を実行してもHENSU1、HENSU2には「0」が格納されていて

とお書きですが、掲載のコードには%HENSU1% %HENSU2%がないので、おそらく、コピペミスで、実際にHENSU2の値を確認したのは、

CMD

1rem 初期化 2set OUTPUT_PATH=D:\TEST 3set HENSU1=0 4set HENSU2=0 5 6for %%a in (*.pdf) do ( 7 8 for /f "delims=_ tokens=1-2" %%A in ("%%a") do ( 9 set HENSU1=%%A 10 set HENSU2=%%B 11 echo 1:%OUTPUT_PATH%\%HENSU2:~0,4% 12 echo 2:%OUTPUT_PATH%\%HENSU2:~0,4%\%%A 13 if not exist %OUTPUT_PATH%\%HENSU2:~0,4% ( 14 mkdir %OUTPUT_PATH%\%HENSU2:~0,4% 15 ) 16 ) 17)

のようなコードだったのではないかと思います。
6行目のforから末尾の)までが1つの大きな文です。%HENSU2%%HENSU2:~0,4%の値取り出しは、一般の言語のようにその文に制御か移った時ではなくて、6行目のforから末尾までの大きな1文の構文解析の直前に行われます。この時点では値は0なので、そのように変数名が値0に置き換わります。その次にfor文が実行されます。C等をご存じなら文単位ではありますが#defineで定義するマクロみたいなものと思ってください(構文解析前に置換されるという意味で)。

このことは、set /?で表示される環境変数についての説明の後半に例文付きで分かり易く説明されています。

対策としては、
案1:set /?に出てくる「遅延環境変数の展開」を使う(普通の言語の「変数」と同じに使える))
案2:大きな文を作らず、小さい文を沢山並べる
の2通りあります。
案1の方針だと、

CMD

1rem ↓ 案1だとこのsetlocalが重要 2setlocal enabledelayedexpansion 3 4set OUTPUT_PATH=D:\TEST 5set HENSU1=0 6set HENSU2=0 7 8for %%a in (*.pdf) do ( 9 for /f "delims=_ tokens=1-2" %%A in ("%%a") do ( 10 set HENSU1=%%A 11 set HENSU2=%%B 12 echo 1:%OUTPUT_PATH%\!HENSU2:~0,4! 13 echo 2:%OUTPUT_PATH%\!HENSU2:~0,4!\%%A 14 if not exist "%OUTPUT_PATH%\!HENSU2:~0,4!" ( 15 mkdir %OUTPUT_PATH%\!HENSU2:~0,4! 16 ) 17 ) 18)

if not existのif文の構文解析は、!HENSU2:~0,4!の変数展開の前に行われるので、ファイル名の所を二重引用符で囲む必要があります(これは構文解析時にはクォートされてないカンマなどは空白扱いされるため)。案1だと、こういう細かい配慮が必要になるケースがあります。

私自身は案2を使うことが多いのですが、案2は、「複数の文をまとめる括弧( )を使わない」、あるいは厳密には、「複数の文をまとめる括弧( )の中では括弧内で更新される環境変数の%による参照をしない」ということで、

CMD

1前略 2for %%a in (*.pdf) do ( 3 for /f "delims=_ tokens=1-2" %%A in ("%%a") do call :FOO %%a %%A %%~B 4) 5exit /b 6 7:FOO 8rem ↓このFILENAMEが %%a 相当 9set FILENAME=%1 10set HENSU1=%2 11set HENSU2=%3 12以下略

のようにforの中味をサブルーチン:FOOにして、:FOOの中では文をまとめる括弧を使わずに書きます。

なお、%%B:~0,4%のような、「forの制御変数」に対しての部分文字列取り出しや文字列置換機能はありません。

投稿2024/07/15 11:12

編集2024/07/16 08:42
otn

総合スコア85458

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

taka0920

2024/07/16 04:04

回答いただき、ありがとうございました。 初めはVBScriptで作成しようと考えたのですが、社内の仕組みで使用する関係上、Microsoft非推奨のものは使うことができず、PowerShellは知見がまったくないため、コマンドラインのバッチ処理で作成する方向となりました。 丁寧に教えていただきありがとうございました。 普通言語の変数のように扱える案1のほうで作成してみようと思います。
otn

2024/07/16 08:58 編集

今のコードを書き換えるなら、案1が楽なのですが、 > if not existのif文の構文解析は、!HENSU2:~0,4!の変数展開の前に行われるので、ファイル名の所を二重引用符で囲む必要があります の部分、引用符で囲まなかった場合に出るエラーメッセージから、「これは引用符を付けなかったために出たエラーだ」と気づけるかどうかですね。まあ、試行錯誤しているうちに解決するかも知れませんが、途中で「この方向では駄目ではないか?」とか思って諦めちゃうと駄目ですね。 案2だと今のコードからの書き換えがやや面倒ですが、回答に書いたように、単純なバッチが読み書きできるスキルがあれば十分だと思います。 > 初めはVBScriptで作成しようと考えたのですが、社内の仕組みで使用する関係上、Microsoft非推奨のものは使うことができず、 環境が許せば、VBAはありかと思いますが、サーバー機だとOffice入ってないか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.40%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問