Tôi có mẫu sau trong một chuỗi (địa chỉ IP):
123.444.888.235
Tôi muốn thay thế số cuối cùng sau dấu chấm bằng 0
, để nó trở thành:
123.444.888.0
Làm thế nào tôi có thể làm điều đó trong bash
hoặc ngôn ngữ kịch bản shell khác?
Tôi có mẫu sau trong một chuỗi (địa chỉ IP):
123.444.888.235
Tôi muốn thay thế số cuối cùng sau dấu chấm bằng 0
, để nó trở thành:
123.444.888.0
Làm thế nào tôi có thể làm điều đó trong bash
hoặc ngôn ngữ kịch bản shell khác?
Câu trả lời:
Trong bất kỳ vỏ POSIX nào:
var=123.444.888.235
new_var="${var%.*}.0"
${var%pattern}
là một nhà điều hành được giới thiệu ksh
vào những năm 80, được chuẩn hóa bởi POSIX cho sh
ngôn ngữ tiêu chuẩn và hiện được triển khai bởi tất cả các hệ vỏ giải thích ngôn ngữ đó, bao gồm cả bash
.
${var%pattern}
mở rộng đến nội dung $var
tước chuỗi ngắn nhất khớp với mẫu ở cuối chuỗi (hoặc giống như $var
khi mẫu đó không khớp). Vì vậy ${var%.*}
(trong đó .*
một mẫu có nghĩa là dấu chấm theo sau bởi bất kỳ số lượng ký tự nào) mở rộng ra $var
mà không có quyền nhất .
và những gì theo sau nó. Ngược lại, ${var%%.*}
nơi chuỗi dài nhất phù hợp với mẫu bị tước sẽ mở rộng sang $var
không có phần bên trái nhất .
và phần tiếp theo chuỗi .
${var%.*}
man bash
và nhấn enter, sau đó nhập /suffix pattern
và nhấn enter. :)
new_var="${var%.*}.0"
... nJoy!.
Một vài cách (tất cả đều cho rằng bạn muốn thay đổi bộ số cuối cùng trong chuỗi):
$ echo 123.444.888.235 | awk -F'.' -vOFS='.' '{$NF=0}1;'
123.444.888.0
Ở đây, -F'.'
nói awk
để sử dụng .
như là dấu tách trường đầu vào và -vOFS='.'
sử dụng nó làm dấu tách trường đầu ra. Sau đó, chúng tôi chỉ cần đặt trường cuối cùng ( $NF
) thành 0 và in dòng ( 1;
là awk
viết tắt của "in dòng hiện tại").
$ echo 123.444.888.235 | perl -pe 's/\d+$/0/'
123.444.888.0
Các -p
kể perl
để in mỗi dòng đầu vào sau khi áp dụng các kịch bản do -e
. Bản thân đoạn mã chỉ là một toán tử thay thế đơn giản sẽ thay thế một hoặc nhiều số ở cuối dòng bằng 0
.
$ echo 123.444.888.235 | sed 's/[0-9]*$/0/'
123.444.888.0
Cùng một ý tưởng trong sed
, sử dụng [0-9]
thay vì \d
.
Nếu chuỗi của bạn nằm trong một biến và bạn sử dụng trình bao hỗ trợ các chuỗi ở đây (chẳng hạn như bash
hoặc zsh
chẳng hạn), bạn có thể thay đổi ở trên thành:
awk -F'.' -vOFS='.' '{$NF=0}1;' <<<$var
perl -pe 's/\d+$/0/' <<<$var
sed 's/[0-9]*$/0/' <<<$var
Cho rằng đầu vào của bạn là một địa chỉ IP, và rằng bạn đang thay thế octet cuối cùng của địa chỉ đó với .0
, sau đó tôi giả định những gì bạn đang thực sự cố gắng để đạt được là để tính toán phần mạng của địa chỉ IP, sử dụng 255.255.255.0
mặt nạ mạng.
Chỉ cần thay thế octet bằng 0 là ổn nếu chiều dài netmask của bạn chia hết cho 8, nhưng đây không phải là trường hợp chung. Nếu bạn cần thực hiện thao tác này cho bất kỳ netmask (mạng con) hợp lệ nào, thì bạn có thể làm một cái gì đó như thế này:
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
Điều này xác định 3 chức năng:
d2i()
chuyển đổi dạng thập phân rải rác của một địa chỉ IP (hoặc mặt nạ) thành một số nguyên đơn giảni2d()
thực hiện ngược lại - chuyển đổi một số nguyên đơn giản thành một số thập phân rải rácipmask()
chỉ cần tính toán một chút VÀ của một địa chỉ và một mặt nạ mạng để cung cấp phần mạng của một địa chỉ. Bash hy vọng các toán hạng của &
là số nguyên.Hai cuộc gọi để ipmask
hiển thị cách mạng có thể được tính từ một địa chỉ IP cho hai mặt nạ khác nhau.
Lưu ý như đã nêu trong câu hỏi, 123.444.888.235
là một địa chỉ IP không hợp lệ. Tôi đã sử dụng 123.44.88.235
thay thế cho các ví dụ này.