Ganti string setelah titik terakhir di bash

12

Saya memiliki pola berikut dalam string (alamat IP):

123.444.888.235

Saya ingin mengganti angka terakhir setelah titik dengan 0, sehingga menjadi:

123.444.888.0

Bagaimana saya bisa melakukannya dalam bashbahasa shell script lain?

Ari
sumber
1
Di mana string-string itu? Dalam variabel bash? Dalam file teks satu per baris?
Stéphane Chazelas
Itu dalam sebuah variabel. Maaf saya lupa menyebutkannya.
Ari
3
Jika itu adalah alamat IP, maka 444 dan 888 adalah nilai oktet yang tidak valid.
Trauma Digital

Jawaban:

24

Dalam setiap shell POSIX:

var=123.444.888.235
new_var="${var%.*}.0"

${var%pattern}adalah operator yang diperkenalkan oleh kshpada tahun 80an, distandarisasi oleh POSIX untuk shbahasa standar dan sekarang diimplementasikan oleh semua shell yang menafsirkan bahasa itu, termasuk bash.

${var%pattern}memperluas ke konten $vardilucuti dari string terpendek yang cocok dengan pola dari ujungnya (atau sama seperti $varjika pola itu tidak cocok). Jadi ${var%.*}(di mana .*merupakan pola yang berarti dot diikuti oleh sejumlah karakter) memperluas ke $vartanpa-paling tepat .dan apa yang mengikutinya. Sebaliknya, di ${var%%.*}mana string terpanjang yang cocok dengan pola dilucuti akan diperluas ke $vartanpa yang paling kiri .dan apa yang mengikutinya.

Stéphane Chazelas
sumber
Apa ? ${var%.*}
Suara
@ tjt263, pada tipe baris perintah man bashdan tekan enter, lalu ketik /suffix patterndan tekan enter. :)
Wildcard
Menambahkan beberapa kutipan setelah posting Anda : new_var="${var%.*}.0"... nJoy !.
8

Ini seharusnya bekerja.

echo 123.444.888.235 | sed 's/\([0-9]*\.[0-9]*\.[0-9]*\.\)[0-9]*/\10/'

Perhatikan bahwa bidang sedsubstitusi terakhir \10,, adalah pola yang cocok pertama kali ( \1), disatukan dengan nol literal.

Kira
sumber
5

Beberapa cara (ini semua mengasumsikan bahwa Anda ingin mengubah set angka terakhir dalam string):

$ echo 123.444.888.235 | awk -F'.' -vOFS='.' '{$NF=0}1;'
123.444.888.0

Di sini, -F'.'diperintahkan awkuntuk digunakan .sebagai pemisah bidang input dan -vOFS='.'menggunakannya sebagai pemisah bidang keluaran. Kemudian, kami hanya mengatur bidang terakhir ( $NF) ke 0 dan mencetak garis ( 1;adalah awksingkatan untuk "mencetak baris saat ini").

$ echo 123.444.888.235 | perl -pe 's/\d+$/0/'
123.444.888.0

The -pmemberitahu perluntuk mencetak setiap baris masukan setelah menerapkan script yang diberikan oleh -e. Script itu sendiri hanyalah operator substitusi sederhana yang akan menggantikan satu atau lebih angka di akhir baris 0.

$ echo 123.444.888.235 | sed 's/[0-9]*$/0/'
123.444.888.0

Gagasan yang sama sed, menggunakan [0-9]alih-alih \d.


Jika string Anda dalam variabel dan Anda menggunakan shell yang mendukung string di sini (seperti bashatau zshmisalnya), Anda dapat mengubah hal di atas menjadi:

awk -F'.' -vOFS='.' '{$NF=0}1;' <<<$var
perl -pe 's/\d+$/0/' <<<$var
sed 's/[0-9]*$/0/' <<<$var
terdon
sumber
5

Kasus umum untuk menerapkan netmask ke alamat IP:

Karena input Anda adalah alamat IP, dan Anda mengganti oktet terakhir dari alamat itu .0, maka saya berasumsi apa yang benar - benar ingin Anda capai adalah menghitung bagian jaringan dari alamat IP, menggunakan 255.255.255.0netmask.

Mengganti oktet dengan nol tidak masalah jika panjang netmask Anda dapat dibagi 8, tetapi ini bukan kasus umum. Jika Anda perlu melakukan operasi ini untuk netmask (subnet) yang valid, maka Anda dapat melakukan sesuatu seperti ini:

function d2i() {
    echo $(( 0x$( printf "%02x" ${1//./ } ) ))
}

function i2d() {
    h=$( printf "%08X" "$1" )
    echo $(( 0x${h:0:2} )).$(( 0x${h:2:2} )).$(( 0x${h:4:2} )).$(( 0x${h:6:2} ))
}

function ipmask() {
    i2d $(( $( d2i $1 ) & $( d2i $2 ) ))
}

ipmask 123.44.88.235 255.255.255.0     # outputs 123.44.88.0
ipmask 123.44.88.235 255.255.255.240   # outputs 123.44.88.224

Ini mendefinisikan 3 fungsi:

  • d2i() mengubah bentuk desimal bertitik dari alamat IP (atau mask) menjadi integer sederhana
  • i2d() melakukan yang sebaliknya - mengonversi bilangan bulat sederhana ke desimal bertitik
  • ipmask()hanya menghitung bitwise AND dari alamat dan netmask untuk memberikan bagian jaringan dari alamat. Bash mengharapkan operan &menjadi bilangan bulat.

Dua panggilan untuk ipmaskmenunjukkan bagaimana jaringan dapat dihitung dari alamat IP untuk dua topeng yang berbeda.


Catatan seperti yang dinyatakan dalam pertanyaan, 123.444.888.235adalah alamat IP yang tidak valid. 123.44.88.235Sebagai gantinya saya menggunakan contoh-contoh ini.

Trauma Digital
sumber
0

sedJawaban alternatif :

sed -r 's/(.*\.).*/\10/'

Ini mengelompokkan semuanya hingga titik terakhir dan mengganti baris penuh dengan konten grup diikuti oleh 0.
Saya menggunakan -r untuk menghindari keharusan melarikan diri kurung.

Harun
sumber