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

このQ&Aのポイント
  • 変数をループ内で変更し、ループ外でも参照したい場合について質問します。Linuxのシェルスクリプトでループ内で変数の値を変更してもループ外でその変更が反映されない問題にぶつかりました。パイプを使用したループでは変数のスコープが異なる為、変更した値をループ外で参照することができませんでした。
  • 現在の回避策として、フラグファイルを使用する方法や一時ファイルを作成して行をスキップする方法を検討していますが、これらの方法はエレガントではありません。そこで、パイプを使用したループ内で変更した変数の値をループ外で参照する方法や、1行をスキップする方法が他にあるのかを質問したいと思います。
  • また、現在使用している方法として、`awk "(NR>=2){print}" ${FILE}`という方法で1行をスキップしていますが、もっと適切な方法があれば教えていただきたいです。
回答を見る
  • ベストアンサー

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

変数をループ内で変更しループ外でも参照したい 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}」 と書いていますが、これは妥当でしょうか? よりよい記述があればあわせて教えてください。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.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

mibusys
質問者

お礼

# 単に1行とばすだけなら # tail -n +1 ${FILE} # で十分。 tailでできるんですね。 「tail -n +2 ${FILE}」で実現できました。 ありがとうございました。 # if […]; の判定の部分が別の方法でできるなら サンプルでは記述していないのですが実はループ内で、 他にも処理をしています。また、この部分は2重ループの中身です。 記述しているループ部分では 行をスペース区切りで分解し、1番目のフィールドに記述されている 正規表現に該当した場合には、2番目のフィールドの文字列を 外側のループの対象の文字列の後ろに付加し標準出力する、 という処理を行なっています。 やや複雑で説明が面倒なのと、伝わりにくそうだったので 問題となっている部分だけをピックアップして質問しました。 隠された全体が多く説明不足な質問ですみません。 awkは複数行にわたるようなスクリプトはあまり書きたくない と(なんとなく)思っていました。でも、awkのほうが (はるかに)適しているように感じました。 awkで記述する方向でも考えてみます。 参考になりました。ありがとうございました。

関連するQ&A

  • While 二重ループ処理について

    Bashのシェルスクリプトでwhileを使いループの処理を行いたい。 現状以下のようにファイルAの中に値”1”とイコールの場合に$awkを表示しています。 これを値”1”部分へファイルBの中の値を順にチェックできるようにしたいのです。 while IFS="$LF" read $READ_R record; do IFS='; ' set -- $record for awk in $3; do if [ "$awk" == "1" ]; then for awk in $4; do echo "$awk" done fi done done < "$1" 初心者のため分かり難い質問かもしれませんがよろしくお願いします。

  • awk外で宣言した変数の参照

    kshを使用して、以下のようなシェルを作成しています。 しかしawk内で$iと$iiが参照出来てない様子です。 どのようにすれば参照できますでしょうか。 ■シェルの中身 #/usr/bin/ksh for i in `cat /tmp/hoge |awk -F : '{ print $3 }' | sort | uniq -d` do if [ $i != "" ]; then for ii in `cat /tmp/hoge` do echo $ii |awk -F ":" '{ if ( $3 -eq $i ) print $ii }' done fi done ■エラー awk: 0602-562 フィールド $() が正しくありません。 入力の行番号は 1 です。 ソースの行番号は 1 です。

  • テキストファイルの行抽出

    linux環境のプログラムについて質問です。 ある特定のファイル(テキストファイル)内のデータで 指定の行を抽出する方法を教えていただきたいと思います。 現在はawkを使用してbashスクリプト内で下記のように head, tailを使用していますが、処理が重いように 感じます。perlまたはawkなどで行抽出の軽い処理は できないでしょうか? (他のunixコマンドでも結構です。) ---------------------------------------- RNUM=`awk 'END{print NR}' $1` #行番号取得 for iwl in `seq 1 $RNUM`;do BASE=`head -n $iwl $1 | tail -n 1` done #iwl ---------------------------------------- Fortran, Cなども使えますが、色々組み合わせて使う上で bash内のスクリプトで行ないたいと思います。

  • awkでn行目までを1行に入れたい

    awkを使ってこの問題を解決できるかどうか教えてください。 次のようなファイルがあるとします。 各行には第1フィールドしか値がありません。 $cat aaa 11111 22222 33333 44444 55555 66666 このファイルを次のように並べ替えたいです。 11111 22222 33333 44444 55555 66666 3行目までの値を1行目に入れ、 次の4行目から6行目までの値を2行目に入れていきたいです。 使用する環境は、solaris,Linuxの混在環境です。 awkで実現できるのではないかと考えていますが、もしできなければその他の方法を教えて頂ければありがたいです。 宜しくお願いします。

  • awkで列指定をして削除

    awkかsedを利用して以下のファイルを処理したいです。 1 2 3 4 5 2 1 3 4 5 1 2 3 4 5 3 1 3 4 5 一列目の値が1の行のみ削除したいです。 2 1 3 4 5 3 1 3 4 5 こんな感じです。 実際に処理するファイルは膨大な行数ががあるためprintでは難しいです。 よろしくお願いします。

  • 変数をループで扱うには??

    C言語を最近勉強し始めたばっかりの初心者ですが、教えてください。 for文を用いたループ処理を使って、以下のことをやりたい場合、打開策があれば教えてください。 理想としては、(下手な書き方であることは100も承知なのですが・・) int i1,i2,i3,・・・・,; (添え字のような雰囲気の)整数変数と、カウント用の変数(例えば int count;)を用意して、 for (count = 1 ;(略);count++)などとして、forのブロック内に『気持ちとしては』、 int(count) = (略) としたいのです。何というか、添え字(正確に言えば全く添え字ではないのですが)とループを同時に扱いたいのです。 この、「添え字のように扱う」という方法・技術があれば、教えてください。お願いします。 「そんな書きかたをせずにこうすれば・・・」っていうのはわかっているんですが、気分的にもスッキリしたいので、回答のほど、お願いします。

  • [awk]2つのファイルを参照して1つのファイルに出力する方法

    最近プログラミング(シェル、awk)を始めた者です。 かなり大まかなものは作れるようになったのですが、急遽、大規模なデータ整理を行わないといけなくなってしまったため、皆さんの知恵を貸していただきたく質問いたしましたm(_ _)m 以下に示すような2つのファイルがあります。 (file1)         (file2) 1 6           1  1  2  10 11 2 3           2  3  5  7  8 3 5           3  6  2  12 13 4 1           4  9  4  5  19 5 2           5  10 19 1  5 6 4           6  4  8  2  9 file1を上から1行ずつ順に読んでいき、2列目の値と同じものをfile2の1列目から探します。合致したところで、file2の合致した行の2列目以降を行番号を付けて表示するというものです。 (「file1の2列目の値=file2の1列目の値」を探し、file2の合致行の値を出力。) 上記ファイルですと、結果的に 1  4  8  2  9 2  6  2  12 13 3  10 19 1  5 4  1  2  10 11 5  3  5  7  8 6  9  4  5  19 という具合になります。 2つのファイルの行数は同じではなく、また、両ファイルとも1列目が行番号というだけで、他の列の値に規則性はありません。 file2の行数は100万以上の大規模なものになります。 自分が作ったものを掲載できればよかったのですが、あいにく会社のPC内にありまして、持ち出しできないため、掲載できません。 動作環境はLinux(RedHat)になります。 他のプログラミング言語についてはまだ分からないため、awkもしくはシェルでお願いいたします。

  • awkで行ごとの計算について

    HP-UX,UNIX環境です。 あるファイルを⇒a.txtとします。 a.txtには以下のような記述だとします。(行は複数行) 20110322000000 00:00:00 PERFORMANCE all 20110322000100 00:00:00 PERFORMANCE all 20110322000200 00:00:00 PERFORMANCE all 20110322000300 00:00:00 PERFORMANCE all shでのループ処理は以下のようにしたいです。 (1)2行目の1カラム目から1行目の1カラム目を引き算、 (2)計算結果をファイルにリダイレクト (3)4行目の1カラム目から3行目の1カラム目を引き算 (4)計算結果をファイルにリダイレクト ※awkを使えば出来そうですが、やり方がわかりません。 お手数ですが、ご回答宜しくお願い致します。

    • ベストアンサー
    • CGI
  • awkでのsh処理について

    HP-UX環境、UNIXです。 1行目の11カラム目にOUTが含まれているかつ2行目の11カラム目にINが含まれている行だけ ファイルに出力するという処理を以下のように考えたんですが、うまくいきません。 awk'{m == NR % 2} m==1{if($11~ "OUT")} && m==0{if($11~ "IN") print $0} ' [ファイル名] 文法的に誤っていますでしょうか?? 回答宜しくお願い致します。

    • ベストアンサー
    • CGI
  • 配列をループでたくさん宣言したいのですが、配列名や変数名を変数で宣言することはできませんか?

    お世話になっております。 タイトル通りの質問です。 日付がファイル名になっているCSVファイルが複数あるのですが、 それをそのまま「array20071020」などという名前の配列に、それぞれ入れて行きたいと思います。ループ処理でなければ出来ないと思うのですが、ループ処理内で配列を宣言していく方法はあるでしょうか。