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 bashhoặ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 bashhoặ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 kshvào những năm 80, được chuẩn hóa bởi POSIX cho shngô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 $vartước chuỗi ngắn nhất khớp với mẫu ở cuối chuỗi (hoặc giống như $varkhi 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 $varmà 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 $varkhông có phần bên trái nhất .và phần tiếp theo chuỗi .
${var%.*}
man bashvà nhấn enter, sau đó nhập /suffix patternvà 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à awkviế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 -pkể 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ư bashhoặc zshchẳ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.0mặ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 để ipmaskhiể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.235là một địa chỉ IP không hợp lệ. Tôi đã sử dụng 123.44.88.235thay thế cho các ví dụ này.