質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
シェルスクリプト

シェルスクリプトは、UNIX系のOSもしくはコマンドラインインタプリタ向けに記述されたスクリプト。bash/zshといったシェルによって実行されるため、このように呼ばれています。バッチ処理などに使用されており、テキストファイルに書かれた命令を順に実行します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

Solaris

Solarisは、SunSoft社が開発・販売を行っているUnix系のOSです。Sun Microsystems社製コンピュータで動作し、またPC/AT互換機で動作するバージョンもあります。旧名称は「SunOS」ですが、現在はSolarisのカーネル部分をSunOSと呼んでいます。

AWK

AWKは、UNIX 上で開発されたプログラミング言語で、CSVファイルなどのテキストファイルの処理を目的にデザインされています。

Q&A

解決済

2回答

3101閲覧

awkコマンドを使用する同一のシェルスクリプトをSolarisとLinuxでそれぞれ実行したところ、異なる実行結果が返ってきてしまう

m_takahumi

総合スコア3

シェルスクリプト

シェルスクリプトは、UNIX系のOSもしくはコマンドラインインタプリタ向けに記述されたスクリプト。bash/zshといったシェルによって実行されるため、このように呼ばれています。バッチ処理などに使用されており、テキストファイルに書かれた命令を順に実行します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

Solaris

Solarisは、SunSoft社が開発・販売を行っているUnix系のOSです。Sun Microsystems社製コンピュータで動作し、またPC/AT互換機で動作するバージョンもあります。旧名称は「SunOS」ですが、現在はSolarisのカーネル部分をSunOSと呼んでいます。

AWK

AWKは、UNIX 上で開発されたプログラミング言語で、CSVファイルなどのテキストファイルの処理を目的にデザインされています。

0グッド

0クリップ

投稿2021/06/17 02:47

編集2021/06/17 07:09

SolarisサーバからLinuxサーバへのマイグレーションを行っており、現行サーバ下で運用しているシェルの稼働検証を行っているのですが、
一部のシェルで現行と異なる実行結果が返ってきてしまい、原因調査を行っております。

挙動を確認すると「awkコマンドでパターンに正規表現を使用して抽出を行う」部分で現行と異なる判断が行われているようなのですが、
その原因が「awkコマンド」なのか、「正規表現」の表し方なのか、メタ文字の使い方なのかが分からず、困っております。
(他にも現行環境下で稼働しているシェルスクリプトが多くあり、それらも同様に修正の必要があるのか調査・判断したい)

どなたかお知恵を拝借できないでしょうか。よろしくお願いいたします。

前提・実現したいこと

SolarisとLinuxで挙動が異なった原因を知りたい。
※問題のシェル自体はif文内にカッコ()を追加したことで現行と同様の結果が返ってきたが、その理由が知りたい
(また、他にもSolarisサーバからLinuxサーバへの移管時にシェルスクリプトの修正が発生しうる要素や確認すべき事項があれば。。。)

発生している問題・エラーメッセージ

以下"input.txt"のようなカンマ区切りのデータがあり、2番目の項目("AAAAAAAAAAA ")を読み取って入力値チェックを行いたい。
現行Solarisサーバでは"1"(値セットあり)が返ってくるのだが、新Linuxサーバで実行したところ、"0"(値セットなし)が返ってきた。
※シェル自体は途中で異常終了せず正常に終了している

該当のソースコード

■input.txt

10,AAAAAAAAAAA ,BBBBBBBB ,CCCCCC ,

■hoge.sh

#!/bin/sh (略) CMD=`awk -F, '{ if ( ! $2 ~ /[^ \t ]/ ) { print "0" } else { print "1" } }' < "input.txt"` (略)

■実行結果

0

試したこと

上記シェルのif文中に()を追加したところ、現行と同様の挙動をするようになった。
⇒だが、なぜLinuxではここに()が必要となるのか分からない("!"が条件の否定ではなくメタ文字として扱われてしまっている?)

■hoge-2.sh

#!/bin/sh (略) CMD=`awk -F, '{ if ( ! ($2 ~ /[^ \t ]/) ) { print "0" } else { print "1" } }' < "input.txt"` (略)

■実行結果

1

追記(2021/06/17 15:12)

SolarisサーバとLinuxサーバでawkの処理結果に差異があるのか確認するため、上記hoge.shの問題の条件式の上に以下コマンドを追記して再度実行したところ、両環境で同一の文字列が出力されているため、awkによる文字列抽出の問題ではなく、if文中の"!"の扱いが異なっている?

cat "input.txt" | awk -F, '{print $1}' >> awktest.log cat "input.txt" | awk -F, '{print $2}' >> awktest.log cat "input.txt" | awk -F, '{print $3}' >> awktest.log cat "input.txt" | awk -F, '/[^ \t ]/ {print $2 }' >> awktest.log cat "input.txt" | awk -F, '/[^ \t ]/ {print $3 }' >> awktest.log

■実行結果

10 JHHTTTTTT11 ITRTTT11 JHHTTTTTT11 ITRTTT11

補足情報(FW/ツールのバージョンなど)

■現行 OS:Solaris
Oracle Corporation SunOS 5.11 11.2
/bin/csh

■移行先 OS:Linux
Red Hat Enterprise Linux release 8.2 (Ootpa)
GNU Awk 4.2.1, API: 2.0 (GNU MPFR 3.1.6-p2, GNU MP 6.1.2)
/bin/bash

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2021/06/17 02:50

それぞれのawkコマンドの種類やバージョンは分かりますか?
m_takahumi

2021/06/17 03:12

申し訳ありません。移行先環境のAwkバージョンは分かったのですが、現行環境のバージョンが分かりません。 (/usr/bin配下にawkがあることは確認したが、"awk --version"コマンドを実行すると返ってこない) Server% /usr/bin/awk awk: Usage: awk [-Fc] [-f source | 'cmds'] [files] Server% /usr/bin/awk -V (応答なし)
yambejp

2021/06/17 04:57

solarisを含めunix系のawkは複数種類があって動作が微妙に違うのですが いまさらsolarisのawkのバージョンをどうこうしてもLinuxで動かない のであれば同じなので、古いことは忘れたほうがよいでしょう。 仕様をきめてLinuxで動作することだけに専念して下さい
m_takahumi

2021/06/17 06:21

上記<試したこと>にも記載したように、該当のシェルスクリプト自体は条件式にカッコを追加したことで希望通りの稼働をするようになったのですが、他にもawkを使用しているシェルスクリプトが大量にあるので、それらについても修正が必要なのかどうかを判断するために、今回なぜこのような違いが出たのか突き止めたかったのです。ただ、今回はどうやらawkの問題ではなくOSの違いによる問題のように思われます。
KojiDoi

2021/06/17 06:26

それぞれの環境で使っているシェルは何でしょうか?
m_takahumi

2021/06/17 07:08 編集

いろいろと情報不足で申し訳ないです。 現行Solaris環境は/bin/csh、移行先Linux環境は/bin/bashです。 【訂正】実行シェルhoge.shの先頭で"#!/bin/sh"とshebangしておりました。失礼いたしました。
guest

回答2

0

ベストアンサー

まず最初にこの問題は(シェルスクリプトの中に埋め込まれている)awk スクリプトの問題であるため、シェルスクリプトとは全く関係がありません。Solaris 11.4 の環境で調べた所デフォルトの awk は 関数が使えないようなので POSIX に準拠してない歴史的な awk のようです。要するに Solaris で使ってる awk が(相当)古い実装であるということです。Solaris には POSIX に準拠した新しい awk も含まれているのですがそれは使われていないようです。Solaris でも 歴史的な awk (/usr/bin/awk) の代わりに POSIX に準拠した awk (/usr/xpg4/bin/awk) を使うと Linux と同じ挙動になります。

以下の結果より ! 演算子の優先順位が違うというよりも文法の解釈そのものが違っている気がします。

gawk の場合

sh

1echo a | gawk '{ if ( ! $0 ~ /b/ ) { print 0 } else { print 1 } }' 21 3 4echo a | gawk '{ if ( $0 ~ /b/ ) { print 0 } else { print 1 } }' 51 6 7echo a | gawk '{ if ( (! $0) ~ /b/ ) { print 0 } else { print 1 } }' 81 9 10echo a | gawk '{ if ( ! ($0 ~ /b/) ) { print 0 } else { print 1 } }' 110

Solaris awk の場合

sh

1echo a | awk '{ if ( ! $0 ~ /b/ ) { print 0 } else { print 1 } }' 20 3 4echo a | awk '{ if ( $0 ~ /b/ ) { print 0 } else { print 1 } }' 51 6 7# 優先順位が違うだけならシンタックスエラーにはならないはず 8echo a | awk '{ if ( (! $0) ~ /b/ ) { print 0 } else { print 1 } }' 9awk: syntax error near line 1 10awk: illegal statement near line 1 11awk: bailing out near line 1 12 13echo a | gawk '{ if ( ! ($0 ~ /b/) ) { print 0 } else { print 1 } }' 140

私は実務で Solaris を使ったことはなく個人的な目的のためのテスト環境として時々使ってるだけなので調べた限りの知識となりますが Solaris 環境は古い環境との互換性を重視しており、デフォルト状態では POSIX 準拠ではなく歴史的な動きをする方のコマンドを優先して使用するようになっているようです。POSIX に準拠した新しいコマンドは /usr/xpg6/bin または /usr/xpg4/bin 以下にインストールされています。このパスは getconf PATH で取得可能で、このパスを環境変数 PATH に設定することで Solaris を POSIX に準拠した環境として使うことが出来ます。

歴史的な方 の awk が呼び出されていることから、上記のような POSIX に準拠させるための設定は行われていないと推測します。その場合 awk 以外にも歴史的な動作するコマンドを使ってる可能性が高いです。移行先の Linux のコマンドは POSIX に準拠しているため動きが異なる可能性があります。つまり /usr/xpg6/bin または /usr/xpg4/bin 以下にあるコマンドと同じファイル名のコマンドを使っている場所は互換性に注意が必要です。今回は ! 演算子の問題のようですが、その他にも正規表現やメタ文字にの挙動に違いがないとは言い切れません。

投稿2021/06/17 07:38

ko1nksm

総合スコア11

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m_takahumi

2021/06/17 08:07

awkスクリプトのバージョン違いによる問題であったことがよく分かりました。 分かりやすい説明に実際の実行結果までつけていただき、非常に勉強になりました。 なんとお礼を申し上げてよいやら、感謝の言葉もありません。 今回はご回答いただきありがとうございました。こちらをベントアンサーとさせていただきます。 また機会がありましたらよろしくお願いいたします。
guest

0

!は単項演算子なので、二項演算子である~より結合度が高いです。つまり、
! $2 ~ /[^ \t ]/は、(! $2) ~ /[^ \t ]/と同じで、$2がそういう内容だと`0 ~ /[^ \t ]/になるので真ですね。

! ($2 ~ /[^ \t ]/)のような意図であるなら、普通は$2 !~ /[^ \t ]/と書きます。

Solarisで偽となったと言うことですかね。理由はちょっとわかりませんが、演算子の結合度が違うとは考えられないので、!"AAAAAAAAAAA "の結果が0でないのですかね?

投稿2021/06/17 03:29

otn

総合スコア84498

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m_takahumi

2021/06/17 08:02

そもそも現行の条件式の書き方がよろしくなく、ある意味Linuxでの挙動が正しい(条件判断=真となる)ということがよく分かりました。理解が浅くお恥ずかしい限りです。ご回答いただきありがとうございました。 また機会がありましたらよろしくお願いいたします。
otn

2021/06/17 08:08

回答では「考えられない」と書いてしまいましたが、 今まで期待通り動いていたのであれば、「Solarisのawkは単項演算子!より二項演算子~の方が結合度が高い」という可能性もありますね。そうであれば奇妙な感じですが。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問