文字列が数値かどうかをテストする

文字列が数値かどうかをテストする

これは簡単なはずです。ただ[[ "$var" =~ '^[1-9][0-9]*$' ]]。私はスクリプトが実行されるシステムを制御しないので、合理的なシェル(Solarisの以前のBourneシェルではない)の移植性が問題です。以下はいくつかのテストです。

% zsh --version
zsh 4.3.10 (x86_64-redhat-linux-gnu)
% zsh -c "[[ 100 =~ '^[1-9][0-9]*\$' ]] && echo OK"
OK
% sh --version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
% sh -c "[[ 100 =~ '^[1-9][0-9]*\$' ]] && echo OK" 
% bash --version
GNU bash, version 4.2.53(1)-release (x86_64-unknown-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
% bash -c "[[ 100 =~ '^[1-9][0-9]*\$' ]] && echo OK"
% ksh --version
  version         sh (AT&T Research) 93u+ 2012-08-01
% ksh -c "[[ 100 =~ '^[1-9][0-9]*\$' ]] && echo OK"
% 

何か抜けたようです。何?

答え1

文字列が数値かどうかをテストする

これには正規表現は必要ありません。ステートメントを使用して、case文字列をワイルドカードパターンと一致させます。正規表現ほど強力ではありませんが、ここでは十分です。バラより私の正規表現がXでは動作しますが、Yでは動作しないのはなぜですか?ワイルドカードパターン(グローブ)が正規表現構文とどのように異なるかについての要約が必要な場合。これはすべてのsh実装(POSIX Bourne以前のバージョンを含む)で機能します。

case $var in
  '' | *[!0123456789]*) echo >&2 "This is not a non-negative integer."; exit 2;;
  [!0]*) echo >&2 "This is a positive integer. I like it.";;
  0*[!0]*) echo >&2 "This is a positive integer written with a leading zero. I don't like it."; exit 2;;
  *) echo >&2 "This number is zero. I don't like it."; exit 2;;
esac

ケースポータブル

すべてのUnixシステムにはshが実装されています。アンティーク以外のUnixまたはPOSIXシステムには、(ほとんど)次のsh実装があります。POSIX仕様。通常はLinuxにありますが、古代のBourneシェルや最新のPOSIX shなど、/bin/shいくつかの商用ユニスもあります。/bin/sh/usr/posix/bin/sh

それがあなたに合わない場合は、#!/usr/bin/env sh実用的なポータブルコードとして使用できます。#!/bin/sh

[[ … ]]POSIX sh では使用できません。 ksh93、mksh、bash、zsh では使用できますが、/bin/shdash (Linux で人気) または BusyBox (組み込み Linux で人気) では使用できません。/bin/shPortable shには組み込みの正規表現一致がなく、ワイルドカード一致のみがあります。 grep、awk、または sed を使用して、POSIX システムから正規表現一致を取得できます。

正規表現の引用=~

=~Ksh93、bash、およびzshには、条件式に正規表現一致演算子があります[[ … ]]。引用規則は少し異なります。

=~Bash ≥3.1では、正規表現文字は引用符がない場合にのみ演算子の右側に特殊効果があります。 so[[ 100 =~ ^[1-9][0-9]*$ ]]はtrueですが[[ 100 =~ '^[1-9][0-9]*$' ]]falseです(部分文字列を含む文字列[[ $x =~ '^[1-9][0-9]*$' ]]のみが一致)。^[1-9][0-9]*$

ksh 93uの正規表現で文字を引用する効果は、文字によって異なります。ワイルドカードでもある文字は引用してはいけませんが、そうでない文字は一重引用符や二重引用符を使用して引用できます(ただし、前にバックスラッシュが来ることはできません)。 so[[ 100 =~ ^[1-9][0-9]*$ ]]は true で、 so は false[[ 100 =~ '^'[1-9][0-9]*'$' ]]ですが[[ 100 =~ '^[1-9][0-9]*$' ]](子文字列を含むすべての項目と一致[1-9][0-9]*[[ 100 =~ ^[1-9][0-9]*\$ ]]、偽でもあります(ゼロ以外の数字で始まり、より多くの数字と a で始まるすべての文字列と一致$)。

zshでは、すべての正規表現文字を引用符で囲むか、引用符を解放できます。これは、文字通り文字を含めるには、アスタリスクと一致する、\\*またはなどの2段階参照が必要であることを意味します。'\*'だからと[[ 100 =~ ^[1-9][0-9]*$ ]]両方が[[ 100 =~ '^[1-9][0-9]*$' ]]正しいです。

正規表現を変数に入れることがシェル関数に依存しない最も安定した方法だと思います。

regex='…' # Use extended regular expression syntax here, with '\'' if you need a literal apostrophe
if [[ $string =~ $regex ]]; …

正規表現/ワイルドカード角括弧式の範囲

一致範囲は[0-9]実装とロケールによって異なります。一般的に言って、0123456789だけが一致すると期待することはできません。 (もちろん一致すると仮定できますが)少なくともそれら)。 0123456789のみを一致させることが重要な場合は、範囲の使用を避け、文字名を個別に指定してください。

関連情報