Bukan yang termudah , tetapi Anda dapat melakukan sesuatu seperti:
$ IP=109.96.77.15
$ echo "$((${-+"(${IP//./"+256*("}))))"}&255))"
109
$ echo "$((${-+"(${IP//./"+256*("}))))"}>>8&255))"
96
$ echo "$((${-+"(${IP//./"+256*("}))))"}>>16&255))"
77
$ echo "$((${-+"(${IP//./"+256*("}))))"}>>24&255))"
15
Yang harus bekerja di ksh93 (mana yang ${var//pattern/replacement}
Operator berasal dari), bash
4.3+, busybox sh
, yash
, mksh
dan zsh
, meskipun tentu saja di zsh
, ada pendekatan lebih sederhana . Di versi yang lebih lama bash
, Anda harus menghapus kutipan dalam. Ini bekerja dengan kutipan batin yang dihapus di sebagian besar kerang lain juga, tetapi tidak ksh93.
Asumsi itu $IP
berisi representasi quad-desimal valid dari alamat IPv4 (meskipun itu juga akan berfungsi untuk representasi quad-hexadecimal seperti 0x6d.0x60.0x4d.0xf
(dan bahkan oktal dalam beberapa shell) tetapi akan menampilkan nilai dalam desimal). Jika konten $IP
berasal dari sumber yang tidak dipercaya, itu akan berarti kerentanan injeksi perintah.
Pada dasarnya, seperti yang kita mengganti setiap .
di $IP
dengan +256*(
, kita akhirnya mengevaluasi:
$(( (109+256*(96+256*(77+256*(15))))>> x &255 ))
Jadi kita membangun integer 32 bit dari 4 byte seperti alamat IPv4 pada akhirnya adalah (meskipun dengan byte terbalik)) dan kemudian menggunakan >>
, &
operator bitwise untuk mengekstrak byte yang relevan.
Kami menggunakan ${param+value}
operator standar (di sini $-
yang dijamin akan selalu ditetapkan) alih-alih hanya value
karena parser aritmatika akan mengeluh tentang kurung yang tidak cocok. Shell di sini dapat menemukan penutup ))
untuk pembukaan $((
, dan kemudian melakukan ekspansi di dalam yang akan menghasilkan ekspresi aritmatika untuk dievaluasi.
Dengan $(((${IP//./"+256*("}))))&255))
gantinya, shell akan memperlakukan kedua dan ketiga )
s ada sebagai penutup ))
untuk $((
dan melaporkan kesalahan sintaks.
Di ksh93, Anda juga dapat melakukan:
$ echo "${IP/@(*).@(*).@(*).@(*)/\2}"
96
bash
, mksh
, zsh
Telah menyalin ksh93 ini ${var/pattern/replacement}
Operator tapi tidak yang menangkap-kelompok penanganan bagian. zsh
mendukungnya dengan sintaks yang berbeda:
$ setopt extendedglob # for (#b)
$ echo ${IP/(#b)(*).(*).(*).(*)/$match[2]}'
96
bash
mendukung beberapa bentuk penanganan grup tangkap di operator pencocokan regexp , tetapi tidak dalam ${var/pattern/replacement}
.
POSIXly, Anda akan menggunakan:
(IFS=.; set -o noglob; set -- $IP; printf '%s\n' "$2")
Untuk noglob
menghindari kejutan buruk untuk nilai $IP
suka 10.*.*.*
, subkulit untuk membatasi ruang lingkup perubahan tersebut ke opsi dan $IFS
.
¹ Alamat IPv4 hanya integer 32 bit dan 127.0.0.1 misalnya hanyalah salah satu dari banyak (meskipun yang paling umum) representasi tekstual. Alamat IPv4 tipikal yang sama dari antarmuka loopback juga dapat direpresentasikan sebagai 0x7f000001 atau 127.1 (mungkin yang lebih tepat di sini adalah 1
alamat pada jaringan 127.0 / 8 kelas A), atau 0177.0.1, atau kombinasi lain dari 1 ke 4 angka yang dinyatakan sebagai oktal, desimal atau heksadesimal. Anda dapat mengirimkan semua itu ping
misalnya dan Anda akan melihat mereka semua melakukan ping localhost.
Jika Anda tidak keberatan efek samping menetapkan variabel sementara sewenang-wenang (di sini $n
), di bash
atau ksh93
atau zsh -o octalzeroes
atau lksh -o posix
, Anda dapat mengkonversi semua representasi mereka kembali ke integer 32 bit dengan:
$((n=32,(${IP//./"<<(n-=8))+("})))
Lalu ekstrak semua komponen dengan >>
/ &
kombinasi seperti di atas.
$ IP=0x7f000001
$ echo "$((n=32,(${IP//./"<<(n-=8))+("})))"
2130706433
$ IP=127.1
$ echo "$((n=32,(${IP//./"<<(n-=8))+("})))"
2130706433
$ echo "$((n=32,((${IP//./"<<(n-=8))+("}))>>24&255))"
127
$ perl -MSocket -le 'print unpack("L>", inet_aton("127.0.0.1"))'
2130706433
mksh
menggunakan bilangan bulat 32 bit yang ditandatangani untuk ekspresi aritmatika, Anda dapat menggunakannya di $((# n=32,...))
sana untuk memaksa penggunaan angka 32 bit yang tidak ditandatangani (dan posix
opsi untuknya mengenali konstanta oktal).
IFS
untuk diread
sana:IFS=. read -a ArrIP<<<"$IP"