利用規約の変更について

変数をループ内で変更しループ外でも参照したい

Linuxのシェルを作成している最中にちょっとした壁にぶつかりました。


元々は以下のような感じの処理でした。
(A)------------------
FLAG=false
awk "(NR>=2){print}" ${FILE} | while read LINE_STR
do
if […]; then
FLAG=true
fi
done
--------------------

状況によってFLAGの値を変更し、あとの処理で
FLAGの値に応じて異なる処理を行ないます。

で、少し調べたところパイプすると別プロセスになるので云々と
あったのでループの前の定義でも中でも「export FLAG」と
書いてみたのですがダメでした。そういうもんじゃないのかと。

元々は、最初の1行は読み飛ばしたいという要望を持っていたので
このような記述だったのですが、少し不本意ですが、
読み込むファイルの1行目も処理対象に含めることにした上で
以下のような記述に変更したところ一応動きました。

(B)------------------
while read LINE_STR
do
FLAG=true
done < ${FILE}
--------------------

対処療法として今はこのようなコードにしましたが完全ではありません。
今自分の知識の中で実現可能な方法だと以下のような感じです。
・フラグファイルを使用する
・1行読み飛ばした一時ファイルを作成しそれを使う
・読み込むファイルの仕様を変更し1行目のヘッダを削除する
・(B)の方法で読み込み、ループ内でカウンタを持ち、最初だけ
 continueする

どれでも一応実現は可能ですが、エレガントではありません。


そこで質問することにしました。
以下のどちらかもしくはそれ以外で私の希望を実現する方法を
教えてください。よろしくお願いします
・パイプを使用したループでループ内で変更した変数の値を取得する方法
 ※(シェルの制約で出来ないのであれば、その旨を知りたいです)
・パイプを使用せず、1行読み飛ばす方法


※そもそも1行読み飛ばす方法で
「awk "(NR>=2){print}" ${FILE}」
と書いていますが、これは妥当でしょうか?
よりよい記述があればあわせて教えてください。
よろしくお願いします。

このQ&Aに関連する最新のQ&A

A 回答 (1件)

単に1行とばすだけなら


tail -n +1 ${FILE}
で十分。

if […]; の判定の部分が別の方法でできるなら(例えば、 grep + 正規表現で判定できる)

if ( tail -n +1 ${FILE} | grep -q '正規表現' )
then
FLAG=true
else
FLAG=false
fi

awk使っているのなら、判定もawkでやってしまうとか

if awk '
BEGIN {flag=1}
(NR>=2){
if ([....での条件判定相当のもの..]) {
flag=0;exit ;
}
}
END {
exit flag;
}
' ${FILE}
then
FLAG=true
else
FLAG=false
fi
    • good
    • 0
この回答へのお礼

# 単に1行とばすだけなら
# tail -n +1 ${FILE}
# で十分。

tailでできるんですね。
「tail -n +2 ${FILE}」で実現できました。
ありがとうございました。


# if […]; の判定の部分が別の方法でできるなら

サンプルでは記述していないのですが実はループ内で、
他にも処理をしています。また、この部分は2重ループの中身です。

記述しているループ部分では
行をスペース区切りで分解し、1番目のフィールドに記述されている
正規表現に該当した場合には、2番目のフィールドの文字列を
外側のループの対象の文字列の後ろに付加し標準出力する、
という処理を行なっています。

やや複雑で説明が面倒なのと、伝わりにくそうだったので
問題となっている部分だけをピックアップして質問しました。
隠された全体が多く説明不足な質問ですみません。


awkは複数行にわたるようなスクリプトはあまり書きたくない
と(なんとなく)思っていました。でも、awkのほうが
(はるかに)適しているように感じました。

awkで記述する方向でも考えてみます。


参考になりました。ありがとうございました。

お礼日時:2010/09/01 13:29

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aと関連する良く見られている質問

Qbashでの変数の引渡し方法

bashを使用するのが初めてなので教えてください。
shellscriptの中で変数を設定するのに共通変数設定用の子Shellを実行して変数を設定したいと思っていますが、うまく動きません。どのように設定したらいいのでしょうか。cshのときはsetenvでよかったのですが。。

親shell(hoge.sh)
--------------
#!/bin/sh
./setenv.sh #変数設定用子Shell

echo $USER
exit 0
--------------

子Shell(setenv.sh)
--------------
#!/bin/sh
USER="hoge"
exit 0
--------------

実行すると以下のようになります。
$./hoge.sh
USER: not found

Aベストアンサー

ご希望のような事を行いたい場合、変数を設定するスクリプト(質問での子シェルsetenv.sh)を「. filename」のような感じでシェルスクリプト(質問での親シェルhoge.sh)で指定します。

ちなみに「. filename」と指定すると、filenameで指定されたファイルから1行ずつ読み出し実行してくれます。

質問にあるシェルスクリプトを修正すると下記のような感じになります。

○hoge.sh
--------------
#!/bin/sh
. ./setenv.sh #変数設定用子Shell

echo $USER
exit 0
--------------

○setenv.sh
--------------
#!/bin/sh
USER="hoge"
--------------

%./hoge.sh
hoge

Qbashなどのシェル変数の値に改行を含める事は可能でしょうか?

タイトルの通りですが、通常のシェル変数の値として

 [prompt]$ aaa="bbb<改行>ccc"

のようなセットを行い、

 [prompt]$ echo $aaa
 bbb
 ccc
 [prompt]$

のような結果を得たいのですが、可能でしょうか。

Aベストアンサー

可能です.
というか,やってみたら出来ることがわかると思います.こんなところで聞くより早い.
なお,sh/bash系では改行文字は特にエスケープせずそのまま入れられます.

aaa='bbb
ccc'

Qsedの置換文字に変数を使用したいのですが・・・

あるファイルの特定の文字を変換し、上書きをする処理を行いたいのですが、sedの置換文字に変数が渡せなくて困っています。

例:
X="a"
Y="b"
echo test.txt | sed 's/${X}/${Y/g}' >test.txt

sedでは置換文字に${X}といった変数を使用することはできないのでしょうか?

Aベストアンサー

' ・・・' で囲まれた中の$はそのままドルマークです。変数展開をするなら、'・・・'で囲んではいけません。

何も囲まないか、"・・・"で囲むかです。

Qシェルでsyntax errorがでてしまう

温度管理をするため、CentOS4.4上で下記のようなスクリプトを動かしています。

---スクリプト始まり---
#!/bin/bash
date=$(date '+%Y/%m/%d(%a)/%R')
rh=$(/var/usbrh/usbrh -1 2>&1)
limit=35
rh_judge=$(echo $rh | cut -c14-15)
if (( ${rh_judge} >= ${limit} )) ;then
alert=alert
else
unset alert
fi
echo ${date} ${rh} ${alert} >> /var/usbrh/usbrh_tes2.log
---スクリプト終わり---
このスクリプトで、ログを出力し、limit以上の数値になった場合、alertがログに書き込まれるようにできました。
そこでコレを少し改良してalert時にメールを飛ばせる様にしたいと思い下記のようにif文を差し替えました。

---if文始まり---
if (( ${rh_judge} >= ${limit} )) ;then
alert=alert
address="xxx@hogehoge.com"
subject="TemperatureAlert"

mail -s $subject $address << END
`$rh`
END
else
unset alert
fi
---if文終わり---

ところが、
echo ${date} ${rh} ${alert} >> /var/usbrh/usbrh_tes2.log
のあとの行(line23)で
line 23: syntax error: unexpected end of fileというのが出て
スクリプトが動かなくなってしまいました。

ログの書き込み部分は問題ないと思うのですが、原因がわかる方いらっしゃいますでしょうか。
ご指摘頂ければ幸いです。
宜しくお願いいたします。

温度管理をするため、CentOS4.4上で下記のようなスクリプトを動かしています。

---スクリプト始まり---
#!/bin/bash
date=$(date '+%Y/%m/%d(%a)/%R')
rh=$(/var/usbrh/usbrh -1 2>&1)
limit=35
rh_judge=$(echo $rh | cut -c14-15)
if (( ${rh_judge} >= ${limit} )) ;then
alert=alert
else
unset alert
fi
echo ${date} ${rh} ${alert} >> /var/usbrh/usbrh_tes2.log
---スクリプト終わり---
このスクリプトで、ログを出力し、limit以上の数値になった場合、alertがログに書き込まれるように...続きを読む

Aベストアンサー

気になるのは `$rh` かなぁ?
$rh に入っている文字列を, コマンドとして実行したいの? もしそうだとしても,
$rh | mail ...
の方が素直じゃないかなぁ.
あと, ヒアドキュメントを終わらせる END の前後に空白がないことも確認してください.

Qシェルスクリプトでファイル内の数値文字列を数値として扱うには

失礼します。
シェルスクリプトでファイル内のテキスト(数値文字列)を取得して、それを使って計算するにはどうすれば良いでしょうか?

str:ファイル内のテキスト(数値文字列)

res=$(( $str + 1 ))

・エラー
")syntax error: invalid arithmetic operator (error token is "


よろしくお願いします。

Aベストアンサー

bashをご使用と判断して

res=$(( $str + 1 ))
ではなく、
res=$(( str + 1 ))
だと思います。

> exprもやってみたのですが、処理が遅くなるので使いません。
興味があって以下のシェルで検証してみました。

#!/bin/bash

str=1
i=0

echo 'Using $((str + 1))'
date '+%H:%M:%S.%N'

while [ $i -lt 10000 ]
do
str=$(( str + 1))
i=`expr $i + 1`
done

date '+%H:%M:%S.%N'

exit

$ ./test.sh
Using $((str + 1))
09:18:46.290418000
09:18:56.929345000
これをexprに書き換えたところ
$ ./test2.sh
Using expr
09:19:00.302748000
09:19:19.259990000

exprだと19秒ですが、$(( 演算 )) だと10秒程度なので、演算が多くなれば確かにexprは不利ですね。

bashをご使用と判断して

res=$(( $str + 1 ))
ではなく、
res=$(( str + 1 ))
だと思います。

> exprもやってみたのですが、処理が遅くなるので使いません。
興味があって以下のシェルで検証してみました。

#!/bin/bash

str=1
i=0

echo 'Using $((str + 1))'
date '+%H:%M:%S.%N'

while [ $i -lt 10000 ]
do
str=$(( str + 1))
i=`expr $i + 1`
done

date '+%H:%M:%S.%N'

exit

$ ./test.sh
Using $((str + 1))
09:18:46.290418000
09:18:56.929345000
これをe...続きを読む

Qsedなどで、特定の文字列の後の文字列を抽出したい

sedなどで、特定の文字列の後の文字列を抽出したい

シェルスクリプト内で、sedなどを使って特定の文字列の後の文字列を抽出したいのですが、どうすればいいでしょうか?

たとえば、abcXYZ123defghiのなかから、XYZの後の「123」を抜き出したいです。

echo abcXYZ123defghi | sed ...

のようにして実行させたいです。

Aベストアンサー

日本語対応sedだと日本語数字混じりでもできますね。

echo abcXYZ12357defghi | sed -e 's/^.*XYZ\([0-90-9]*\).*$/\1/' -e 'y/0123456789/0123456789/'
12357

※ 使っている日本語コードの指定は必要かも(例えば、 --ctype=EUC)

echo abcXYZ12357defghi | sed -e 's/^.*XYZ\([0-90-9]*\).*$/\1/'
12357

※ 入力フォームに書いている時はASCIIと日本語の判別がし易いけど回答見るとわかり難いですね。後ろの例での結果57とy/0123456789/の数字部分が日本語です。


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング

おすすめ情報