きたへふ(Cチーム)のブログ

ファミスタとは特に関係ありません。タブレット・スマホをご利用の方は、できればPCモードで御覧ください。

シェルスクリプトにおけるechoとエスケープシーケンスの扱いについて

2006年10月10日 | サーバ・プログラム
シェルスクリプト総合 その7
http://pc8.2ch.net/test/read.cgi/unix/1157601611/

からの転載。





113 名無しさん@お腹いっぱい。 sage 2006/10/07(土) 10:54:57 
シェル内の変数が0の時の挙動についておしえてください。 

Windowsで使う下記のような内容のバッチファイルを作るために、 
Solaris8上で簡単なスクリプトを作成しますた。 


<バッチファイルの中身 (期待している実行結果)> 
lha32 a D:¥save¥0.lzh D:¥work¥0¥ 
lha32 a D:¥save¥1.lzh D:¥work¥1¥ 
lha32 a D:¥save¥2.lzh D:¥work¥2¥ 
 : 
lha32 a D:¥save¥9999.lzh D:¥work¥9999¥ (←9999部分は、実際は第1引数で指定) 


<作ったスクリプト> 
#!/bin/sh 
COUNT=0 
LAST=$1 
while [ $COUNT -le $LAST ] 
do 
  echo "lha32 a D:¥¥save¥¥$COUNT.lzh D:¥¥work¥¥$COUNT¥¥" 
  COUNT=`expr $COUNT + 1` 
done 


114 続き sage 2006/10/07(土) 10:55:42 
ところがこのスクリプトを実行すると、最初に実行されるCOUNT変数が0のときに 
0の値が消えてしまう現象が出てしまいまつ。(´・ω・`) 

<shの実行結果> 
lha32 a D:¥save.lzh D:¥work    ←0が消えている 
lha32 a D:¥save¥1.lzh D:¥work¥1¥ 
lha32 a D:¥save¥2.lzh D:¥work¥2¥ 
 : 

試しにシェルの種類を変えてみたところ、ksh, zsh は sh と同じ挙動を示し、 
bashのみ期待していた出力となりますた。 

<bashの実行結果> 
lha32 a D:¥save¥0.lzh D:¥work¥0¥ 
lha32 a D:¥save¥1.lzh D:¥work¥1¥ 
lha32 a D:¥save¥2.lzh D:¥work¥2¥ 
 : 


この現象について、 
 ・何故、0が消えるのか? 
 ・/bin/shを使った場合に0を表示させる方法 

について教えてください。 
おまいら、よろしくおながいします。 


115 名無しさん@お腹いっぱい。 sage 2006/10/07(土) 11:39:34 
man echo 



116 名無しさん@お腹いっぱい。 sage 2006/10/07(土) 11:50:42 
>>113 
それは、echoコマンドの仕様が違うため。 
Solarisなどの /bin/sh の echo は、bashの echo -e に相当する。 

echo -e 相当だと、¥ が、シェルと echoで2回解釈されるので、 
単純な ¥ を出力させたければ、¥¥¥¥ と書かないと行けない。 

よって↓で桶。 

echo "lha32 a D:¥¥¥¥save¥¥¥¥$COUNT.lzh D:¥¥¥¥work¥¥¥¥$COUNT¥¥¥¥" 


117 113 sage 2006/10/07(土) 12:08:24 
>>116 
回答ありがとうございますた。 
¥がシェルと echoで2回解釈されるとは知りませんですた…。 


118 名無しさん@お腹いっぱい。 sage 2006/10/07(土) 12:10:55 
¥0になりうる場所のみ二重化すればよいから、 

echo "lha32 a D:¥¥save¥¥¥¥$COUNT.lzh D:¥¥work¥¥¥¥$COUNT¥¥" 

でもいいな。 



119 名無しさん@お腹いっぱい。 sage 2006/10/07(土) 12:42:08 
>>118 
ashとかだと、¥1 でも 8進数の1と解釈するから、それはお勧めできない。 
すべて ¥¥¥¥ にするのが吉。 


120 名無しさん@お腹いっぱい。 sage 2006/10/07(土) 13:00:20 
エスケープだらけでややこしいな。 
echo時は無難な/にでもしといて |sed とかしてまとめてエスケープつけると 
見やすいかも。好きずきだが。 


121 名無しさん@お腹いっぱい。 sage 2006/10/07(土) 13:02:25 
ash(´゜c_,゜` )プッ 
んな中途半端なもん使うなや 

それに¥1になりうるのは¥¥$COUNTのところだけだろ。 



122 名無しさん@お腹いっぱい。 sage 2006/10/07(土) 13:22:46 
D:¥¥save じゃなくて、 
D:¥¥tave とかだったら困るだろ。 
¥¥¥¥ にしとけ。 


123 名無しさん@お腹いっぱい。 sage 2006/10/07(土) 13:24:36 
UNIXのコマンドは¥をエスケープキャラクタとして使用するものが多い。 
ディレクトリ区切りは/としておいて、最後に一括変換すればよい。 

#!/bin/sh 
COUNT=0 
LAST=$1 
while [ $COUNT -le $LAST ] 
do 
  echo "lha32 a D:/save/$COUNT.lzh D:/work/$COUNT/" 
  COUNT=`expr $COUNT + 1` 
done | tr '/' '¥¥' 


124 名無しさん@お腹いっぱい。 sage 2006/10/07(土) 13:38:18 
¥(´゜c_,゜` )プッ 
んな中途半端なもん使うなや 


125 名無しさん@お腹いっぱい。 sage 2006/10/07(土) 19:02:19 
適当に'~'を混ぜて、¥の部分をシェルには解釈させないようにすればいい。 
というかむしろ変数展開部分だけ"~"使え。ややこしいときは。 

echo lha32 a 'd:¥¥save¥¥'"$COUNT.lzh" 'd:¥¥work¥¥'"$COUNT"'¥¥' 


126 名無しさん@お腹いっぱい。 sage 2006/10/07(土) 20:28:15 
echo に関してだけはbashがGJだとおもうな。 
printf があるのに、エスケープシーケンスを解釈してしまうようなままにしとくのがいけない。 
バッドノウハウの典型だな。 



127 名無しさん@お腹いっぱい。 sage 2006/10/07(土) 20:32:36 
やっぱ bash使えば直るよねぇ 


128 名無しさん@お腹いっぱい。 sage 2006/10/07(土) 22:39:17 
echoがエスケープシーケンス解釈しないのはBSD由来なわけだが。 
んで、echoがエスケープシーケンスをデフォルトで解釈するビルドもできちゃう 
どっちつかずなbashがGJなのかよw 


129 名無しさん@お腹いっぱい。 sage 2006/10/08(日) 00:09:40 
デフォルトは有効でもいいが、オプションで無効にできたりするといいがな。 



130 名無しさん@お腹いっぱい。 sage 2006/10/08(日) 01:13:22 
大多数のshができないものは基本無効、オプションで有効だろ? 


131 名無しさん@お腹いっぱい。 sage 2006/10/08(日) 06:43:25 
ちゃうだろ。 
Solarisなどのecho(/bin/echoも含む)が、エスケープシーケンスを無効にする方法がないことをいってるんジャマイカン? 


コメント