[前の記事]« NT4:FOR文内の「IF」構文が期待通りに動作しない
[次の記事]FDの交換を促しながらCOPYをしたい »

関連オンラインソフト配布サイト:
Vector>ダウンロード(top) |>MS-DOSまたは汎用 | >WindowsVista/XP/2000/NT

▲カテゴリー「文字列の操作」索引へ

[NT系]"&"などの特殊記号を含むファイルの文字列の置換方法


423) ファイルの文字列置換について(その2) Miki 2003/07/16(水) 11:57


こんにちは。

DOSに関しては、初心者です。
PCはW2KProを使用しています。

<391)ファイルの文字列置換について>を参考にしてバッチにてファイルの文字列置換を行ってみました。

下記ファイル内容の"Maxpp"という部分を"Minpgm"という感じで置換
させようとして、じゃくさんのsample.bat<403) Re7:あと少しなんですが 参照>を参考にし、実行したところ、置換は出来ているのです
が、私の場合、他の置換に関係ない部分で、何故か上手く動いてくれませんでした。

ファイルの内容(ファイル名:c:\MaxParam\Maxpp.ini)
------------------------------------------------
[#Pcpath]
FtpSrvFileA=C:\Param\FtpSrvA.dat
FtpSrvFileB=C:\Param\FtpSrvB.dat
[#NETWORK]
ProgramPath=C:\Maxpp\
ProgramName=Maxpg.EXE -x C:\Maxpp\ABCDE.PortNo=99
ModemCommand=AT&F
ProccessMode=2
ProccessStatus=0
[#Tanmatsu]
TanmatsuNo=9
[#System]
KanshiKadou=03
KanshiAbend=01
------------------------------------------------

置換後のファイルを確認したところ、

"ModemCommand=AT&F"の部分がModemCommand=ATとなっており、

メッセージとして、

'F'は、内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチファイルとして認識されていません。

と表示されました。また、

"ProccessMode=2"、"ProccessStatus=0"、"TanmatsuNo=9"

の部分が消えてしまっていました。

ファイル内容の構成例としては、上記とほぼ同じなのですが、どのようにバッチに手を加えたらよいか、ご教授下さい。お願いします。



424) Re:ファイルの文字列置換について(その2) じゃく 2003/07/16(水) 13:10


><391)ファイルの文字列置換について>を参考にしてバッチにてファイルの文字列置換を行ってみました。

>下記ファイル内容の"Maxpp"という部分を"Minpgm"という感じで置換
>させようとして、じゃくさんのsample.bat<403) Re7:あと少しなんですが 参照>を参考にし、実行したところ、置換は出来ているのです
>が、私の場合、他の置換に関係ない部分で、何故か上手く動いてくれませんでした。

>ModemCommand=AT&F
>ProccessMode=2
>ProccessStatus=0
>[#Tanmatsu]
>TanmatsuNo=9
>[#System]
>KanshiKadou=03
>KanshiAbend=01
>------------------------------------------------

>置換後のファイルを確認したところ、

>"ModemCommand=AT&F"の部分がModemCommand=ATとなっており、

>メッセージとして、

>'F'は、内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチファイルとして認識されていません。

これは、このバッチでは回避できない問題です。
1行ずつ対象ファイルを読み込み、該当する文字列を置換した後、
echo %l%>>%fname% とする段階で、
echo ModemCommand=AT&F>>c:\MaxParam\Maxpp.ini
と置き換えられるのですが、&がバッチのなかで特殊な機能を
持つ文字になっているため、

echo ModemCommand=AT>>c:\MaxParam\Maxpp.ini
F>>c:\MaxParam\Maxpp.ini

という2つのコマンドと解釈します。
当然Fというコマンドが無いためエラーとなります。

この問題は、このバッチで置き換えを仕様とする以上
回避できませんので、&を含んだファイルの置き換えは
>や<や|と同様できません。

>と表示されました。また、

>"ProccessMode=2"、"ProccessStatus=0"、"TanmatsuNo=9"

>の部分が消えてしまっていました。

ここについては、当方で確認をしましたが再現しませんでした。

いずれにせよ、Mikiさんの希望するファイルでの置き換えなら、
別の方法を考える必要があります。
他のWebページにWSHを使用する方法がありましたのでリンクを
載せておきます。

http://www.atmarkit.co.jp/fwin2k/win2ktips/308strrpl/strrpl.html



425) Re2:ファイルの文字列置換について(その2) じゃく 2003/07/16(水) 13:27


>これは、このバッチでは回避できない問題です。

と書きましたが、
Mikiさんが置換したいファイルに限ってうまく動くように
したいのなら以下のように1行追加すれば動くと思います。

:sub
:この1行下の acb=xyz に置換前と置換後の文字列を指定する。
set l=%line:abc=xyz%
set l=%l:&=^&%
echo %l%>>%fname%
goto :EOF


426) Re3:ファイルの文字列置換について(その2) Miki 2003/07/16(水) 14:04


レスありがとうございます。じゃくさん。

>>"ProccessMode=2"、"ProccessStatus=0"、"TanmatsuNo=9"
>>
>>の部分が消えてしまっていました。
>>
>ここについては、当方で確認をしましたが再現しませんでした。

多分、そのままファイル内容の例をコピーされたのだと思いますが、実は"ProccessMode=2"、"ProccessStatus=0"、 "TanmatsuNo=9"のそれぞれの後ろに1つ空白が入っているかと思いますが、それを削除すると現象が発生するかと思います。(実際には後ろの空 白はありません)

>Mikiさんが置換したいファイルに限ってうまく動くように
>したいのなら以下のように1行追加すれば動くと思います。

>:sub
>:この1行下の acb=xyz に置換前と置換後の文字列を指定する。
>set l=%line:abc=xyz%
>set l=%l:&=^&%
>echo %l%>>%fname%
>goto :EOF

set l=%l:&=^&%を追加して、実行してみました。
しかし現象は変わりませんでした。(ToT)
なんでかな~???

やはりWSHを使用するしかないでしょうか・・・。
スクリプトに関しては手を出したことないので、なるべくなら避けて通りたいな、ってのが本音です。(^^;





428) Re4:ファイルの文字列置換について(その2) ふぇむ 2003/07/16(水) 14:19


>やはりWSHを使用するしかないでしょうか・・・。

文字列置換を行なう比較的汎用な WSHスクリプト(VBScript版)をサンプル的にちょっと書いてみました。

このファイルを、仮に WordRepl.vbs という名前で保存したとします。そうして、DOSコマンドバッチスクリプト内で

cscript //nologo WordRepl.vbs "ターゲットファイルフルパス" "サーチ文字列" "置き換え文字列"

と起動すると、ターゲットファイル内の対象文字列が置換されたテキストが標準出力に出力されるので、それを所望のファイル名でリダイレクトすれば置き換えは実現できると思います。

ターゲットファイルのフルパスは、DOSコマンドバッチ内で与えればよいと思います。

下記スクリプトは、エラー処理等いいかげんなんで、真剣なものにするにはもうちょっとちゃんと組むのが望ましいと思いますが、サンプル程度には動くでしょう。


------------------------------------------------------- WordRepl.vbs

sub WordRepl( filepath , findword , replword )

Set fs = CreateObject( "Scripting.FileSystemObject" )

if fs.FileExists( filepath ) then
dim fo
set fo = fs.OpenTextFile( filepath )
dim all, repl
all = fo.ReadAll()
fo.Close()
set fo = Nothing
repl = Replace( all, findword, replword )
WScript.Echo( repl )
else
WCsript.Echo( "ファイルがありません" )
end if

end sub


Dim WSHArguments
Set WSHArguments = WScript.Arguments
dim filepath
dim searchword
dim replword

if (WSHArguments.Count >= 3) then
filepath = WSHArguments(0)
searchword = WSHArguments(1)
replword = WSHArguments(2)
WordRepl filepath, searchword, replword
end if


429) Re5:ファイルの文字列置換について(その2) ふぇむ 2003/07/16(水) 14:26


>文字列置換を行なう比較的汎用な WSHスクリプト(VBScript版)をサンプル的にちょっと書いてみました。

しかし、sed を使うとこんだけでいいでしょう。

sed 's/abc/xyz/g' "ソースファイル" > "置き換え後ファイル"

abc や xyz の部分は、いわゆる正規表現で書けて、そのため今度は正規表現上意味のあるパターンは正規表現としてのエスケープが必要となりますが、それは比較的シンプルです。



430) Re5:ファイルの文字列置換について(その2) ふぇむ 2003/07/16(水) 14:31


すみません、ちょっとタイプミス。

> WCsript.Echo( "ファイルがありません" )

WScript.Echo の誤りですね。しかしファイルの存在チェック等は DOSコマンドバッチのレベルでやっておけば、ここは関係ないと思います。



427) Re3:ファイルの文字列置換について(その2) ふぇむ 2003/07/16(水) 14:10


>>これは、このバッチでは回避できない問題です。

DOSコマンドバッチスクリプトでは、この "コマンドラインで意味を持つ記号のエスケープ" の問題があって、なかなか汎用なものができにくいので、私としては、ここにこだわってややこしい不安定なスクリプトを組むくらいなら、単なる文字列置換な ら sed の利用を、構文解析+置換 なら awk の利用をおすすめします。もちろん Windows Scripting Host でもよいです。

DOSコマンドバッチのみにこだわるならば、最大の問題は次だと思います。

●set文を利用した文字列置換において、1回の参照で1つのパターンしか置換できない。にもかかわらず、^ でのエスケープは1段階しかできない(2回目の参照では消えている)。

これを回避するためには、^ が消えないように、2回参照する場合は2回めに参照される場合に ^ になるべき部分に ^^ を、3回参照する場合には3回参照される場合に ^ になるべき部分に ^^^^ を、.... というように、^ をいっぱい重ねてエスケープのエスケープのエスケープの、.... と重ねる必要があります。以前そうやって組んでみたこともありますが、かなりややっこしいです。

現実的にチェックすべき記号の数が少ないならば、それを見越して数回のエスケープを行なうようにすればいいのですが、スクリプトのメンテナンス(変更)に対して不安定となりがちです。



431) Re4:ファイルの文字列置換について(その2) Miki 2003/07/16(水) 15:44


レスありがとうございます。ふぇむさん。

VBスクリプトとsedについて両方実施してみました。

まず、VBスクリプトについて・・・

>cscript //nologo WordRepl.vbs "ターゲットファイルフルパス" "サーチ文字列" "置き換え文字列"

>と起動すると、ターゲットファイル内の対象文字列が置換されたテキストが標準出力に出力されるので、それを所望のファイル名でリダイレクトすれば置き換えは実現できると思います。

コマンドプロンプト画面上では置換されていましたが、”ファイル名にリダイレクトする”っていう方法がイマイチ意味がわかりませんでした。具体的にどのようにすればよいでしょうか?

sedについて・・・

コマンドプロンプト画面にて

sed 's/abc/xyz/g' "ソースファイル" > "置き換え後ファイル"

を実行しましたが、置換処理どころか、ファイルの内容が空っぽになってしまいました。(ToT)

実行方法に誤りがあったのでしょうか?それともsed.exeを置いたフォルダの場所が悪かったのでしょうか?

こんな質問ばかりでごめんなさい。m(_ _)m


432) Re5:ファイルの文字列置換について(その2) Miki 2003/07/16(水) 16:24


さきほどのVBScriptのリダイレクトについてですが、

C:\>cscript //nologo WordRepl.vbs c:\MaxParam\Maxpp.ini Maxpp Minpgm > c:\MaxParam\Maxpp.ini

として実行してみましたが、

C:\WordRepl.vbs(9,1) Microsoft VBScript 実行時エラー:ファイルの最後を超えた入力を行おうとしました。

というメッセージが表示され、ファイルの内容は空っぽになっていました。(ToT)
なので、このような指定の仕方じゃないんですよね?


434) Re6:ファイルの文字列置換について(その2) ふぇむ 2003/07/16(水) 16:39


>さきほどのVBScriptのリダイレクトについてですが、

>C:\>cscript //nologo WordRepl.vbs c:\MaxParam\Maxpp.ini Maxpp Minpgm > c:\MaxParam\Maxpp.ini

>として実行してみましたが、

先ほど書いたコメントにも書きましたが、入力ファイルとりダイレクト先のファイルが同じではいけません。 > でリダイレクトを実行するということは、最初にまずそのファイルをカラッポにして書き込みオープンする、ということになると思います。スクリプト実行時に はその入力ファイルはカラッポになった後、です。
サイズ 0 になって当然だと思います。


435) Re7:ファイルの文字列置換について(その2) ふぇむ 2003/07/16(水) 16:58


>サイズ 0 になって当然だと思います。

すみません、読み返すと、上記表現はちょっときつすぎですね。
別に他意なくついさらっと書いてしまいましたが、気分を害されたかもしれません。申し訳ないです。



433) Re5:ファイルの文字列置換について(その2) ふぇむ 2003/07/16(水) 16:36


>コマンドプロンプト画面上では置換されていましたが、”ファイル名にリダイレクトする”っていう方法がイマイチ意味がわかりませんでした。具体的にどのようにすればよいでしょうか?

すみません、テニヲハがちょっと変だったかな...

単に、たとえば

cscript //nologo WordRepl.vbs "ターゲットファイルフルパス" "サーチ文字列" "置き換え文字 列" > "置き換え後ファイル"

とかするっていう意味です。
ちなみに、> で出力先を切り替えることを、リダイレクト、といいます。


>コマンドプロンプト画面にて

>sed 's/abc/xyz/g' "ソースファイル" > "置き換え後ファイル"

>を実行しましたが、置換処理どころか、ファイルの内容が空っぽになってしまいました。(ToT)

"ソースファイル" と "置き換え後ファイル" を同じ名前にしてたりしません?


>sed.exeを置いたフォルダの場所が悪かったのでしょうか?

パスさえ通っていれば、sedコマンドの実体の場所は関係ないと思います。

sed に関しては、 sed -h でコマンドオプションを見てください。
sed -e "sedスクリプト" とかで実行する必要があったかも。

ただ、コマンドラインでの実行だと、またコマンドライン上でのエスケープ問題がからんでくるので、安定的には sed スクリプトを別ファイルにして

sed -f sedスクリプトファイル

で実行するほうがよいと思います。

sed や awk に関しては、分厚い本もありますが、リファレンスとしては、オライリー・ジャパンの 「sed & awk デスクトップリファレンス」(760円)がちっちゃくて薄い割にちゃんと書いてあってよいです。



438) Re6:ファイルの文字列置換について(その2) Miki 2003/07/16(水) 17:49


>>サイズ 0 になって当然だと思います。

>すみません、読み返すと、上記表現はちょっときつすぎですね。

いえいえ、わからない私としては少々キツイ言われ方しても仕方ないですよね。(でも正直、その言葉を見たときは泣きそうでした(;_;))

大変詳しく説明して頂きありがとうございます。
VBScriptについては、よくわかりました。sedの方はよくわかってませんが・・・。
まだまだ勉強不足ですね。いろんなリファレンス読んで頑張ってみます。


441) Re7:ファイルの文字列置換について(その2) ふぇむ 2003/07/16(水) 19:15


>(でも正直、その言葉を見たときは泣きそうでした(;_;))

ああ、やっぱり.... ごめんなさい、書いた時にそこまで気が付かなくて.... もうちょっと読み返してから書き込めばよかったんですが。


>VBScriptについては、よくわかりました。sedの方はよくわかってませんが・・・。

VBScript って書き出すと結構面倒なんですよね....。DOSバッチで一瞬で書けることも、長々と書かなきゃできない。sed や awk なんかがシンプルでいいです。

DOSコマンドバッチの利便性は高いのですが、それだけではカバーしにくい制約もあるので、環境的に許されるならば、sed や awk とか、WSH とか、または他のスクリプト系言語とか、をあわせて使うことで、トータルとして安定でシンプルでメンテナンスしやすいスクリプトが組めると思います。

ついでなんで、理解の一助という意味で、sed についてちょっと補足しておきます。(といっても、私もそんなえらそーに語れるほどの専門家ではないのですが...)


sed って、だいたい次のような使い方でしょうか。結果の標準出力を別のファイルにリダイレクトして保存したり、さらにパイプでつないで次の加工を行なったり、するわけです。

type 【テキストファイル】 | sed 【sedのスクリプト】 →(標準出力に)【sedで加工されたテキストファイル】

sed 【sedのスクリプト】 【テキストファイル】 →(標準出力に)【sedで加工されたテキストファイル】


上記をDOSコマンドバッチの心臓部として、その前処理としてDOSバッチ系でファイルやディレクトリについて操作をする、つまり最上位はDOSバッチコマンドで、その中から sed が呼ばれる、みたいな組み合わせがよいと思います。


sed は「ストリームエディタ」で、もともとUNIXの世界の初期のラインエディタであった ed を、対話的なエディットではなく、バッチ処理的にまとめてエディットができるようにしたもの、です。(エディタ ed はその後 ex になり、スクリーンエディタである vi になっていった)(あってます?有識者の方々^^;)

ベースがラインエディタなので、sed も「テキストファイル1行」の単位で処理します。 sed の世界独特の表記方法やコマンドなどのルールがあり、それに従って編集コマンドを書いたものが、sed のスクリプト、なわけです。sed のスクリプトは、基本的には「1行を加工するコマンドの羅列」です。


sed のスクリプトは、さっきの例 's/abc/xyz/g' だと簡易に1行だけ

コマンド

って感じの形でしたが、実はもっと書けて、


ある行,ある行 {
コマンド
コマンド
....
コマンド
}

ある行,ある行 {
コマンド
コマンド
....
コマンド
}

.......


みたいな形にかけます。ある行からある行までに対し、{} 内の各単位コマンドが各1行に適用され変換されます。

「ある行」は、数字だと最初から数えて何行目、という意味だし、/パターン/ と書くと、そのパターンを含む行、という意味になります。! をくっつけると、「それ以外の行」が対象となるようです。

コマンドは基本的にアルファベット1文字です。s だと文字列置換、d だと行削除、とか。

文字列置換の s は、 s/パターン1/パターン2/オプション という形です。
「その行の中でパターン1にマッチする部分をパターン2で置き換えて出力する」という意味になります。パターン1は正規表現で表します。オプションは、数 字だと「何個目にマッチした部分だけ」という指定(オプションなしだと1と同じ~つまり1個目だけ)、g だと「マッチしたの全部」、という意味になります。パターン1でマッチした一部分をパターン2側で参照する、なんていう書き方もできます。

行のパターン指定と行削除の d をあわせて使うと、grep みたいな使い方もできます。


とてもここで全てを書ききれるものではありませんが、おおむね、上のようなことを知って、正規表現も学んで、いくつか試してみれば、使えるようになってくると思います。

以上、長々とスペース消費し申し訳ありませんでした。
 
 


カテゴリー「文字列の操作」索引へ

 

カテゴリー一覧

FPCU/FPCDIY QUICK LINK online
この上の各ジャンル名をクリックすると、下のウィンドウが切り替わります▼


=リンク集のインデックスはこちら=

資料書籍

About

2003年07月16日 16:21に投稿されたエントリーのページです。

ひとつ前の投稿は「NT4:FOR文内の「IF」構文が期待通りに動作しない」です。

次の投稿は「FDの交換を促しながらCOPYをしたい」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

This site is powered by Six Apart
Movable Type 3.33-ja
このブログについて | 運営:有限会社メディアポート