Thay thế chuỗi sau dấu chấm cuối cùng trong bash


12

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?


1
Những chuỗi đó ở đâu? Trong một biến bash? Trong một tệp văn bản một dòng trên mỗi dòng?
Stéphane Chazelas

Đó là trong một biến. Tôi xin lỗi đã quên đề cập đến nó.
Ari

3
Nếu đó là các địa chỉ IP, thì 444 và 888 là các giá trị octet không hợp lệ.
Chấn thương kỹ thuật số

Câu trả lời:


24

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%.*}
lên tiếng

@ tjt263, tại loại dòng lệnh man bashvà nhấn enter, sau đó nhập /suffix patternvà nhấn enter. :)
tự đại diện

Đã thêm một số trích dẫn sau bài viết của bạn : new_var="${var%.*}.0"... nJoy!.

8

Điều này nên làm việc.

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

Lưu ý rằng trường sedthay thế cuối cùng \10, là mẫu phù hợp đầu tiên ( \1), được nối với một số không.


5

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;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

5

Trường hợp chung để áp dụng netmask cho địa chỉ IP:

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ản
  • i2d() 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ác
  • ipmask()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.


0

Một sedcâu trả lời khác :

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

Nó nhóm mọi thứ cho đến dấu chấm cuối cùng và thay thế dòng đầy đủ bằng nội dung của nhóm theo sau là 0.
Tôi sử dụng -r để tránh phải thoát dấu ngoặc đơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.