- PR -

シェルスクリプト バッククォーテーション内の処理。

投稿者投稿内容
みきにゅう
会議室デビュー日: 2004/07/28
投稿数: 9
投稿日時: 2005-09-15 15:20
いつもお世話になっています。

シェルスクリプト(bash)で、ファイルのある部分だけを抜き出す
スクリプトを作っています。

例えば…
---
A 100 aaa
B 200 bbb
C 300 ccc
---
というようなファイルの2列目(100, 200, 300)が200以下の
1列目(A, B)を抜き出したいです。


---
M1=A
M2=B
M3=C
i=1
while [ i -le 3 ]
do
if [ `cat <FILE_NAME> | sed -e 's/ */ /g' | grep $( eval echo "\$M$i" ) | cut -d" " -f2` -le 200 ]; then
echo "\$M$i"
fi
i=`expr $i + 1`
done
---

こんな感じで作ってみたました。
そうすると、if の左辺でうまくgrepされず、2列目の値が全て
格納されてしまって、"(比較対象の)引数が多すぎる"という
エラーになってしまいました。

echo $(eval echo "\$M$i") …@
だけで実行すると、一列目の値(A,B,C))がひとつだけ返ってくるのですが、、

A=`echo $(eval echo "\$M$i")` …A
echo $A
だと、iと同じ値(1, 2, 3)が返ってきます。
iと同じ値(1, 2, 3)でgrepされてしまう為、ifの左辺に2列目の値が
全て格納されてしまうようです。

@とAの違いがわからなかったので色々調べてみたのですが、
どうしてもわかりませんでした。

@とAはシェル内部の処理的にはどのように異なるのでしょうか?

わかりづらい説明ですみませんが、よろしくお願いします。

[ メッセージ編集済み 編集者: みきにゅう 編集日時 2005-09-15 15:21 ]
非武装エリア
大ベテラン
会議室デビュー日: 2004/03/03
投稿数: 202
お住まい・勤務地: 日本・たこ部屋
投稿日時: 2005-09-15 17:12
/tmp/dataにデータがあるとして awk を使って

awk '$2 <= 200 { print $0}' /tmp/data

ってのは駄目?
angel
ぬし
会議室デビュー日: 2005/03/17
投稿数: 711
投稿日時: 2005-09-15 17:20
こんにちは。
そいつは、quoting hell ってやつじゃないかと思います。

例題:grep により、\. という文字列を正確に検索せよ。( ただし、fgrep や grep -F はズルと見なす )
選択肢:
 (1) grep '\.' /tmp/file
 (2) grep "\." /tmp/file
 (3) grep '\\.' /tmp/file
 (4) grep "\\." /tmp/file
 (5) grep '\\\\.' /tmp/file
 (6) grep "\\\\." /tmp/file

こういうのに頭を痛めれば、何となく見えてくると思います。

ただし一寸感想を申し上げますと、

 ・何ゆえ $(〜) を使わずに `〜` を使うのでしょう??
 ・そもそも、プログラムとして見たときに、元のスクリプトの処理はとても不自然では??

私は、この路線でスクリプトを直していくのはお勧めしません。

以上、ご参考まで。

追記:
出した例は、ちっとも quoting hell では無かったですね。申し訳ないです。
どちらかと言うと、こういう例が良いかも

Level0. # perl -e 'print "hoge\n"'
Level1. # su -c "perl -e 'print \"hoge\\n\"'"
Level2. # su -c "su -c \"perl -e 'print \\\"hoge\\\\n\\\"'\""
Level3. # su -c "su -c \"su -c \\\"perl -e 'print \\\\\\\"hoge\\\\\\\\n\\\\\\\"'\\\"\""


眠れない夜にどうぞ。

[ メッセージ編集済み 編集者: angel 編集日時 2005-09-15 18:29 ]
みきにゅう
会議室デビュー日: 2004/07/28
投稿数: 9
投稿日時: 2005-09-15 19:33
非武装エリアさん、angelさん ご返信ありがとうございます。
返信が遅くなってしまい、申し訳ありません。

>非武装エリアさん
ご教示頂いた"awk"を使うことを思いつきませんでした。
awkを使って作りなおしてみたら、わたしの期待する結果が得られました。

>angelさん
ご提示頂きました例題をただ今試行錯誤中です。
"quoting hell"という言葉も初めて聞きました…。

 >・何ゆえ $(〜) を使わずに `〜` を使うのでしょう??
ただいつもの習慣で`〜`を使ってしまいました。
ご指摘頂いた$(〜)との違いがまだわからないです。

 >・そもそも、プログラムとして見たときに、元のスクリプトの処理はとても不自然では??
作っているときから、こんなロジックでいいのかな?とは思っていましたが
他に思いつかなかったので、あんな感じになってしまいました。


例題や今回まだわたしがわかっていないところが理解できたら、答えを書き込もうと思います。
もしお目にする事がありましたら、ご指摘などいただければ幸いです。
#そんなコトを書き込んで目ざわりになってしまったらすみません。。
angel
ぬし
会議室デビュー日: 2005/03/17
投稿数: 711
投稿日時: 2005-09-15 20:00
こんばんは。
引用:
 >・何ゆえ $(〜) を使わずに `〜` を使うのでしょう??
ただいつもの習慣で`〜`を使ってしまいました。
ご指摘頂いた$(〜)との違いがまだわからないです。


なるほどです。いえ、`〜` の中で $(〜) を使っていたもので、あれ? と思いまして。
違いは特に無いですが、断然 $(〜) の方が使いやすいです。`〜` を入れ子にすることを考えれば一発です。( それが quoting hell )

引用:
 >・そもそも、プログラムとして見たときに、元のスクリプトの処理はとても不自然では??
作っているときから、こんなロジックでいいのかな?とは思っていましたが
他に思いつかなかったので、あんな感じになってしまいました。


ちょっとキツイ物言いで、気分を害されたかもしれませんが、シェルスクリプトでも、非武装エリアさんの awk スクリプトのような簡潔なモノは作れます。
逆に出来ないようなら、シェルスクリプトではなく、別の手を考えた方が良いと思ってまして。

例:
while read First Second Other
do
[ "$Second" -le 200 ] && echo "$First"
done < ファイル名

引用:
"quoting hell"という言葉も初めて聞きました…。


実は私もはじめて使いました。咄嗟に思いついた言葉でして、今まであまり見たことは無いです。ただ、海外のサイトで使用している例はあるようです。
思考実験としては面白いのですが、実務でコレを気にするのは辛いと思いますよ。
Mattun
ぬし
会議室デビュー日: 2004/08/10
投稿数: 1391
投稿日時: 2005-09-15 22:22
引用:

 >・何ゆえ $(〜) を使わずに `〜` を使うのでしょう??
ただいつもの習慣で`〜`を使ってしまいました。
ご指摘頂いた$(〜)との違いがまだわからないです。


man bash
に書かれてた気がします。
みきにゅう
会議室デビュー日: 2004/07/28
投稿数: 9
投稿日時: 2005-09-16 17:44
返信がおそくなり、申し訳ありません。

引用:
なるほどです。いえ、`〜` の中で $(〜) を使っていたもので、あれ? と思いまして。
違いは特に無いですが、断然 $(〜) の方が使いやすいです。`〜` を入れ子にすることを考えれば一発です。( それが quoting hell )


ご説明と海外のサイトを見てみましたが、quoting hell まだピンときません。
もうちょっと調べてみます。。


引用:
例題:grep により、\. という文字列を正確に検索せよ。( ただし、fgrep や grep -F はズルと見なす )
選択肢:
 (1) grep '\.' /tmp/file
 (2) grep "\." /tmp/file
 (3) grep '\\.' /tmp/file
 (4) grep "\\." /tmp/file
 (5) grep '\\\\.' /tmp/file
 (6) grep "\\\\." /tmp/file


自信ないのですが、こんな感じかなと思います。
 (1) .を検索
 (2) .を検索
 (3) \+任意の一文字を検索
 (4) .を検索
 (5) \\+任意の一文字を検索
 (6) \+任意の一文字を検索
なので、\\.を正確に検索できるものはないのでは…?
\.を正確に検索するには grep '\\\.' /tmp/file かなぁと思います。。


引用:
ちょっとキツイ物言いで、気分を害されたかもしれませんが、シェルスクリプトでも、非武装エリアさんの awk スクリプトのような簡潔なモノは作れます。
逆に出来ないようなら、シェルスクリプトではなく、別の手を考えた方が良いと思ってまして。


そんな事ないです。ご指摘いただけてとてもうれしかったです。
自分だけじゃイマイチなことにすら気がつかないときばっかりですので…。。
非武装エリアさんに教えていただいた方法で作りなおして、なんとか完成しました。
(とってもすっきりして読みやすくなりました。)


引用:
man bash
に書かれてた気がします。


書いてありました。 $, `, \\の扱いが ちょっと違うみたいですね。
やっと理解できました。ありがとうございます。


引用:
追記:
どちらかと言うと、こういう例が良いかも

Level0. # perl -e 'print "hoge\n"'
Level1. # su -c "perl -e 'print \"hoge\\n\"'"
Level2. # su -c "su -c \"perl -e 'print \\\"hoge\\\\n\\\"'\""
Level3. # su -c "su -c \"su -c \\\"perl -e 'print \\\\\\\"hoge\\\\\\\\n\\\\\\\"'\\\"\""


度々ありがとうございます。
明日お休みなので、またじっくり考えてみます。。(むぅ、難しそう…)

#わたしのお勉強みたいになってしまっていますが、みなさんご迷惑じゃないでしょうか?
angel
ぬし
会議室デビュー日: 2005/03/17
投稿数: 711
投稿日時: 2005-09-17 04:21
おはようございます。
引用:
自信ないのですが、こんな感じかなと思います。
…( 中略 )
なので、\\.を正確に検索できるものはないのでは…?
\.を正確に検索するには grep '\\\.' /tmp/file かなぁと思います。。


はい、正解です。
ちょっと意地悪ながら、確かに選択肢内に正解はありません。
\ の数で迷うものを考えて問題を作ったのですが、後で良く見返してみると quoting hell と直接の関係が無いことに気付いたのでした。( なので追記したのです )

引用:
ご説明と海外のサイトを見てみましたが、quoting hell まだピンときません。


あ…、さも一般的な言葉のように書いてしまって申し訳ないですが、言葉どおりの意味しか無いです。意訳すると「クォートの入れ子を考えるのは大変」ってところでしょうか。
ですので、
引用:
引用:
追記:
どちらかと言うと、こういう例が良いかも
…(中略)


度々ありがとうございます。
明日お休みなので、またじっくり考えてみます。。(むぅ、難しそう…)


の感想が出ている時点で、既に quoting hell を実感していることになります。
※ 追記は「問題」ではなく、実際にクォートを多段階に入れ子をした例を書いたものです。より大きいレベルの時どうなるかを考えると…、羊さんを数える代わりになるかも。
※ 多段階の su は現実的ではないかも知れませんが、ssh の遠隔コマンド実行の時に、ssh+コマンド を含んだコマンドを実行することを考える…、など、一寸凝ろうとした時にたまに類似例が出てくるものだと思います。
引用:
#わたしのお勉強みたいになってしまっていますが、みなさんご迷惑じゃないでしょうか?


いえ、こういうのを考えて書くのも、私にとっては勉強ですから。
※ それに嫌だったら、元々コメント書きませんし…。ネタが出ない場合も書き/書けませんが。

[ メッセージ編集済み 編集者: angel 編集日時 2005-09-17 04:24 ]

スキルアップ/キャリアアップ(JOB@IT)