簡単に言えば、Bashスクリプトの文字列が有効なIPアドレスを表すことを確認したいと思います。私は他の多くの人のように正規表現を使ってこれを実行しようとするトラップに陥ったと思います。これはIPv4には十分でしたが、IPv6はより複雑で(ゼロ圧縮をサポートするため)、複雑で特に読みにくいソリューションです。 。
しかし、UnixとLinuxはIPアドレスを明確に理解しているので、bashでIPアドレスをチェックするより良い方法があるかどうか疑問に思います。これを行うために使用できるかなり一般的なツールを使用することをお勧めします。
filter_var
実際にはPHP関数を使用する現在のソリューションを置き換えたいので、他の言語(Pythonなど)を使用したくありません。動作しますが、正規表現と同様に、1つでは使用したくない2番目の言語を紹介します。
0.0.0.0-255.255.255.255
最後に、IPアドレス範囲(例えば、など)も処理するソリューションがあれば理想的でしょうが0.0.0.0/16
、これを直接処理することはできます。
答え1
ipコマンドを使うのはどうですか?
ip route get <ip-address>
無効な場合、戻り値は 1 です。
(2022/9/17)@MaXi32さんのコメントに返信するために、インターネット接続なしで私のLinuxノートブックですばやく確認してみました。ネットワークが閉じると、ip コマンドは無効な IP に対して 1 を返し、有効な IP に対して 2 を返します。
有効なIPの場合:
$ ip route get 192.168.0.255 ; echo $?
RTNETLINK answers: Network is unreachable
2
$ ip route get fd00::192.168.0.255 ; echo $?
RTNETLINK answers: Network is unreachable
2
無効なIPの場合:
$ ip route get 192.168.0.256 ; echo $?
Error: any valid prefix is expected rather than "192.168.0.256".
1
$ ip route get fd00::192.168.0.256 ; echo $?
Error: any valid prefix is expected rather than "fd00::192.168.0.256".
1
IPコマンドバージョン:
$ ip -V
ip utility, iproute2-5.9.0, libbpf 0.3.0
(2022/9/17#2)inet_ptonを使って小さなプログラムを書くことができます。私はこれが良いと思います。次のコードは例から得られます。inet_pton マンページIPをテキストからバイナリに変換しようとし、IPが無効な場合はエラーが発生します。
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char *argv[])
{
unsigned char buf[sizeof(struct in6_addr)];
int domain, s;
char str[INET6_ADDRSTRLEN];
if (argc != 3) {
fprintf(stderr, "Usage: %s {i4|i6|<num>} string\n", argv[0]);
exit(EXIT_FAILURE);
}
domain = (strcmp(argv[1], "i4") == 0) ? AF_INET :
(strcmp(argv[1], "i6") == 0) ? AF_INET6 : atoi(argv[1]);
s = inet_pton(domain, argv[2], buf);
if (s <= 0) {
if (s == 0)
fprintf(stderr, "Not in presentation format");
else
perror("inet_pton");
exit(EXIT_FAILURE);
}
if (inet_ntop(domain, buf, str, INET6_ADDRSTRLEN) == NULL) {
perror("inet_ntop");
exit(EXIT_FAILURE);
}
printf("%s\n", str);
exit(EXIT_SUCCESS);
}
答え2
bash
関連するシステムコールへの直接アクセスが不足している可能性があるため、同様の操作をinet_pton(3)
実行するコールが必要になる場合がありますsipcalc
(さまざまなUNIXのポートまたはパッケージツリーに存在する必要があります)。より高いレベルの言語も呼び出しを受けることができますが、inet_pton(3)
詳細は言語によって異なります。NetAddr::IP
Perlのサブネット関連コード。
答え3
@ktakaの答えによると、ip route get
スクリプトがネットワーク接続に大きく依存しない限り、IPアドレスを確認するために使用しないことをお勧めします。これは、システムのインターネット接続が良好でない場合、またはインターネット接続が完全に切断された場合ip route get
にIPが正しく定義されていても、スクリプトを使用すると常にエラーコード(0以外)を返すためです。
解決策:
@Rolf Randerが提供した手動リンクを見つけましたが、なぜipcalc
Debian 11のバイナリにそのオプションがなく、-c
以前のipcalc
バイナリもそれをサポートしていないのか混乱していたので、マニュアルipv6
でこのキーワードを使用してGoogleを検索しました。作成者のユーザー名ページから取得し、dcantrell ipcalc
公式リンクはここから取得します。
https://gitlab.com/ipcalc/ipcalc
上記のアドレスは、ipcalc
IPv4とIPv6の両方を正式にサポートするIPアドレスです。インストールするには、mesonを含む最新のビルドを使用することをお勧めします(ただし、mesonを使用したくない場合は、以前のmakeビルドも提供します)。
だから私が設定したipcalc
方法は次のとおりですDebian 11
。
既存のipcalcを削除する(既存のバージョンが悪い)
apt-get -y remove ipcalc
rm -rf "/usr/bin/ipcalc"
次に、公式リポジトリからipcalcをインストールします。
apt -y install meson
git clone https://gitlab.com/ipcalc/ipcalc.git
cd ipcalc
meson setup build --buildtype=release
ninja -C build
cp build/ipcalc /usr/bin
apt -y remove meson
ipcalc --version
1.0.1
これでipcalc
IPv4とIPv6を確認できます。
#!/bin/bash
IP="1.1.1.1"
if ipcalc -s -c $IP; then
echo "valid IPv4 or IPv6"
else
echo "Invalid IPv4 or Ipv6"
fi
-s
エラーメッセージを無視し-c
て出力せずに確認
特定のIPv4を確認するには、Check IPv6を使用または-4
使用します-6
。例:
#!/bin/bash
# IP is a valid IPv6
IP="::1"
# But we want to check only IPv4
if ipcalc -s -4 -c $IP; then
echo "valid IPv4"
else
echo "Invalid IPv4"
fi
出力:
Invalid IPv4
私はずっと前からAndroidを使用してきましたsipcalc
が、IPv4とIPv6の両方のチェックを実行していますが、ほとんどの出力が単純で他の目的のためのjson出力があるのでAndroidを好みます。ipv6calc
ipcalc
編集する
(2022年10月23日):
@ktakaの最新のコメントに基づいた主なポイントは、ip route get
インターネットに接続せずに使用するときに次のようなことです。
$ ip route get 192.168.0.255 ; echo $?
RTNETLINK answers: Network is unreachable
2
システムがファイアウォールの背後にある場合、または接続状態が悪い場合、有効なIPは返されません。 IPは有効で、ネットワークに接続できないなど、不要な情報を知らせるのではなく、成功コード0を返す必要があります。
答え4
これはipv4の問題を解決することができます
# check IPv4 syntax
if [[ "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
echo 'Valid IP'
else
echo "Invalid IP: $ip" >&2
exit 1
fi
私は私がインポートしたスクリプトにipv6を実装していますが、完了したらこの投稿を更新します。