web-dev-qa-db-ja.com

UNIXで文字列に数字が含まれているかどうかを確認する

私はUNIXを初めて使用し、今日は仕事を始めたばかりですが、Javaの経験があり、次のコードを使用しています。

#/bin/bash
echo "Please enter a Word:"
read Word
grep -i $Word $1 | cut -d',' -f1,2 | tr "," "-"> output

これは問題なく動作しますが、Wordを読み取るときに、文字だけが含まれていること、および「無効な入力!」という文字が印刷されているかどうかを確認する必要があります。メッセージを送信し、もう一度入力するように依頼します。 ifステートメントを使用した正規表現がこれを行う簡単な方法であると想定しましたが、Javaアプリケーションに慣れているため、UNIXでの使用方法について頭を悩ませることはできません。任意Linuxで正規表現を使用するすべてのソリューションを検索したときにヘルプが見つからなかったため、これを支援していただければ幸いです。すべて数値であるかどうかに関係なく対処できました。

9
electricsheep

さらに別のアプローチ。一致するものが見つかった場合、Grepは0で終了するため、終了コードをテストできます。

echo "${Word}" | grep -q '[0-9]'
if [ $? = 0 ]; then
    echo 'Invalid input'
fi

これは/bin/shと互換性があります。


DaenythとJohnの提案を取り入れると、これは次のようになります。

if echo "${Word}" | grep '[0-9]' >/dev/null; then
    echo 'Invalid input'
fi
18
Stephen P

二重角かっこ演算子は、testコマンドの拡張バージョンであり、=~演算子を介して正規表現をサポートします。

#!/bin/bash

while true; do
    read -p "Please enter a Word: " Word
    if [[ $Word =~ [0-9] ]]; then
        echo 'Invalid input!' >&2
    else
        break
    fi
done

これはbash固有の機能です。 Bashは、UNIXのすべてのフレーバーで使用できるわけではない新しいシェルです。ただし、「新しい」とは「真空管後の時代に最近開発されたばかり」を意味し、「UNIXのすべてのフレーバーではない」とは古いバージョンのような遺物を意味します。 SolarisおよびHP-UXの。

私の意見では、これは最も簡単なオプションであり、bashは最近十分に移植可能ですが、古いUNIXに移植可能であることが実際に重要である場合は、他のポスターのsh互換の回答を使用する必要があります。 shは最も一般的で最も広くサポートされているシェルですが、移植性のために支払う代償は=~のようなものを失っています。

10
John Kugelman

移植可能なシェルコードを作成しようとしている場合、文字列操作のオプションは制限されています。 caseコンストラクトでシェルグロブパターン(正規表現よりも表現力がはるかに低い)を使用できます。

export LC_COLLATE=C
read Word
while
  case "$Word" in
    *[!A-Za-z]*) echo >&2 "Invalid input, please enter letters only"; true;;
    *) false;;
  esac
do
  read Word
done

[〜#〜] edit [〜#〜]LC_COLLATEを設定する必要があります。これは、ほとんどの非Cロケールでは、A-Zのような文字範囲に「明らかな」がないためです。 」の意味。 ASCII文字のみが必要だと思います。発音区別符号付きの文字も必要な場合は、LC_COLLATEを変更せず、A-Za-z[:alpha:]に置き換えてください(したがって、パターン全体が*[![:alpha:]]*)になります。

完全な正規表現については、exprコマンドを参照してください。 [〜#〜] edit [〜#〜]exprには、他のいくつかの基本的なシェルツールと同様に、いくつかの特別な文字列に関する落とし穴があることに注意してください。以下のz文字は、$Wordexprによって予約語として解釈されるのを防ぎます。

export LC_COLLATE=C
read Word
while expr "z$Word" : 'z[A-Za-z]*$' >/dev/null; then
  echo >&2 "Invalid input, please enter letters only"
  read Word
fi

Bashの最近の十分なバージョンのみを対象とする場合は、=~条件付きコマンドの[[ ... ]]演算子などの他のオプションがあります。

最後の行にバグがあることに注意してください。最初のコマンドは

grep -i "$Word" "$1"

引用符は、やや直感に反するため、"$foo"は「fooという変数の値」を意味しますが、プレーンな$fooは「fooの値を取得し、空白を含む別の単語に分割し、各単語をグロブパターンとして扱い、それを拡張してみてください。」 (実際、$Wordに文字のみが含まれていることをすでに確認している場合、引用符を残しても害はありませんが、毎回引用符を付けるよりも、これらの特殊なケースを考えるのに時間がかかります。)

それを行うためのさらに別の(かなり)ポータブルな方法...

if test "$Word" != "`printf "%s" "$Word" | tr -dc '[[:alpha:]]'`"; then
   echo invalid
fi
1
tom

Bashパラメーターの拡張と文字クラスをいじってみましょう。

# cf. http://wiki.bash-hackers.org/syntax/pe

Word="abc1def"
Word="abc,def"
Word=$'abc\177def'
# cf. http://mywiki.wooledge.org/BashFAQ/058 (no NUL byte in Bash variable)
Word=$'abc\000def'   
Word="abcdef"

(
set -xv
[[ "${Word}" != "${Word/[[:digit:]]/}" ]] && echo invalid || echo valid
[[ -n "${Word//[[:alpha:]]/}" ]] && echo invalid || echo valid
)
0
joe

これを行うための1つのポータブルな(bash> = 3と仮定)方法は、すべての数値を削除して長さをテストすることです。

#!/bin/bash
read -p "Enter a number" var
if [[ -n ${var//[0-9]} ]]; then
    echo "Contains non-numbers!"
else
    echo "ok!"
fi

Javaに由来するため、bashにはオブジェクトやデータ型の実際の概念がないことに注意することが重要です。すべてが文字列であり、複雑なデータ構造はせいぜい苦痛です。

私が行ったことやその他の関連機能の詳細については、Googleでbash文字列を操作してください。

0
Daenyth

みんなの答えは、無効な文字は数字だけだという事実に基づいているようです。最初の質問では、文字列に「文字以外は何もない」ことを確認する必要があると述べています。

私はそれを行うための最良の方法はだと思います

nonalpha=$(echo "$Word" | sed 's/[[:alpha:]]//g')
if [[ ${#nonalpha} -gt 0 ]]; then
    echo "Invalid character(s): $nonalpha"
fi

このページで文字列内の数字以外の文字を検出する方法を探している場合(私が行ったように!)、[[:alpha:]]を[[:digit:]]に置き換えます。

0
Joshua