trích xuất một phần của chuỗi bằng cách sử dụng bash / cut / split


121

Tôi có một chuỗi như thế này:

/var/cpanel/users/joebloggs:DNS9=domain.com

Tôi cần trích xuất tên người dùng ( joebloggs) từ chuỗi này và lưu trữ nó trong một biến.

Định dạng của chuỗi sẽ luôn giống nhau ngoại trừ joebloggsdomain.comvì vậy tôi đang nghĩ rằng chuỗi có thể được chia hai lần bằng cách sử dụng cut?

Phần tách đầu tiên sẽ được chia theo :và chúng tôi sẽ lưu phần đầu tiên trong một biến để chuyển cho hàm chia thứ hai.

Lần tách thứ hai sẽ chia theo /và lưu trữ từ cuối cùng ( joebloggs) vào một biến

Tôi biết làm thế nào để làm điều này trong php bằng cách sử dụng mảng và phân tách nhưng tôi hơi mất hứng với bash.

Câu trả lời:


333

Để trích xuất joebloggstừ chuỗi này trong bash bằng cách sử dụng mở rộng tham số mà không cần bất kỳ quy trình bổ sung nào ...

MYVAR="/var/cpanel/users/joebloggs:DNS9=domain.com" 

NAME=${MYVAR%:*}  # retain the part before the colon
NAME=${NAME##*/}  # retain the part after the last slash
echo $NAME

Không phụ thuộc vào joebloggsviệc ở một độ sâu cụ thể trong đường dẫn.


Tóm lược

Tổng quan về một số chế độ mở rộng tham số, để tham khảo ...

${MYVAR#pattern}     # delete shortest match of pattern from the beginning
${MYVAR##pattern}    # delete longest match of pattern from the beginning
${MYVAR%pattern}     # delete shortest match of pattern from the end
${MYVAR%%pattern}    # delete longest match of pattern from the end

Vì vậy, #có nghĩa là phù hợp từ đầu (nghĩ về một dòng chú thích) và %có nghĩa là từ cuối. Một trường hợp có nghĩa là ngắn nhất và hai trường hợp có nghĩa là dài nhất.

Bạn có thể lấy các chuỗi con dựa trên vị trí bằng cách sử dụng các số:

${MYVAR:3}   # Remove the first three chars (leaving 4..end)
${MYVAR::3}  # Return the first three characters
${MYVAR:3:5} # The next five characters after removing the first 3 (chars 4-9)

Bạn cũng có thể thay thế các chuỗi hoặc mẫu cụ thể bằng cách sử dụng:

${MYVAR/search/replace}

patternđịnh dạng giống như đối sánh tên tệp, vì vậy *(bất kỳ ký tự nào) là phổ biến, thường được theo sau bởi một ký hiệu cụ thể như /hoặc.

Ví dụ:

Đưa ra một biến như

MYVAR="users/joebloggs/domain.com" 

Xóa đường dẫn để lại tên tệp (tất cả các ký tự cho đến dấu gạch chéo):

echo ${MYVAR##*/}
domain.com

Xóa tên tệp, để lại đường dẫn (xóa kết hợp ngắn nhất sau cuối /):

echo ${MYVAR%/*}
users/joebloggs

Chỉ lấy phần mở rộng tệp (xóa tất cả trước kỳ trước):

echo ${MYVAR##*.}
com

LƯU Ý: Để thực hiện hai thao tác, bạn không thể kết hợp chúng mà phải gán cho một biến trung gian. Vì vậy, để lấy tên tệp không có đường dẫn hoặc phần mở rộng:

NAME=${MYVAR##*/}      # remove part before last slash
echo ${NAME%.*}        # from the new var remove the part after the last period
domain

Tôi không chắc đây là đối số cho hay chống lại việc sử dụng grep trong sáng tạo, nhưng hãy thử với VAR = / here / is / a / path: with / a / dấu hai chấm / bên trong: DNS9 = domain.com
rici

2
Ngọt! Và nó được thực hiện bên trong trình bao đang thực thi, do đó nhanh hơn so với các trình bao sử dụng các lệnh khác.
stolsvik

3
@Fadi Bạn phải chuyển ký tự đại diện sang trước dấu hai chấm và sử dụng #thay vì %. Nếu bạn muốn chỉ là phần sau dấu hai chấm cuối cùng, sử dụng ${MYVAR##*:}để có được những phần sau dấu hai chấm đầu tiên, sử dụng${MYVAR#*:}
beroe

4
Bạn ơi, không biết bạn đã quay lại câu trả lời này bao nhiêu lần rồi. Cảm ơn bạn!
Joel B

1
Câu trả lời chính xác! Câu hỏi: Nếu mẫu của tôi là một biến, tôi sẽ nhập nó như thế này ${RET##*$CHOP}hay thế này ${RET##*CHOP}(hoặc cách khác)? EDIT: Có vẻ là trước đây,${RET##*$CHOP}
Ctrl S

43

Xác định một chức năng như sau:

getUserName() {
    echo $1 | cut -d : -f 1 | xargs basename
}

Và chuyển chuỗi dưới dạng tham số:

userName=$(getUserName "/var/cpanel/users/joebloggs:DNS9=domain.com")
echo $userName

1
Câu trả lời này đã giúp tôi đạt được những gì tôi đến đây. Không có câu trả lời nào được chấp nhận và câu trả lời này được tôi bỏ phiếu vì sự đơn giản.
harperville

1
Điều chỉnh duy nhất tôi phải làm trong lệnh trên là loại bỏ ':', như thế này echo $1 | cut -d -f 1 | xargs. +1 cho ans đơn giản và gọn gàng.
Bhushan

20

Còn sed thì sao? Điều đó sẽ hoạt động trong một lệnh duy nhất:

sed 's#.*/\([^:]*\).*#\1#' <<<$string
  • Các #đang được sử dụng cho ngăn regex thay vì /kể từ khi chuỗi có /trong đó.
  • .*/ lấy chuỗi đến dấu gạch chéo ngược cuối cùng.
  • \( .. \)đánh dấu một nhóm chụp. Đây là \([^:]*\).
    • Cho [^:]biết bất kỳ ký tự nào _ trừ dấu hai chấm và *có nghĩa là không hoặc nhiều hơn.
  • .* nghĩa là phần còn lại của dòng.
  • \1có nghĩa là thay thế những gì được tìm thấy trong nhóm chụp đầu tiên (và duy nhất). Đây là tên.

Dưới đây là bảng phân tích khớp chuỗi với biểu thức chính quy:

        /var/cpanel/users/           joebloggs  :DNS9=domain.com joebloggs
sed 's#.*/                          \([^:]*\)   .*              #\1       #'

Bóc tách siêu đẹp!
kyb

11

Sử dụng một sed duy nhất

echo "/var/cpanel/users/joebloggs:DNS9=domain.com" | sed 's/.*\/\(.*\):.*/\1/'

10

Sử dụng một Awk duy nhất:

... | awk -F '[/:]' '{print $5}'

Có nghĩa là, sử dụng làm dấu phân tách trường /hoặc :, tên người dùng luôn ở trong trường 5.

Để lưu trữ nó trong một biến:

username=$(... | awk -F '[/:]' '{print $5}')

Cách triển khai linh hoạt hơn với sedđiều đó không yêu cầu tên người dùng phải là trường 5:

... | sed -e s/:.*// -e s?.*/??

Đó là, xóa mọi thứ từ :và xa hơn, và sau đó xóa mọi thứ cho đến cuối cùng /. sedcó lẽ cũng nhanh hơn awk, vì vậy thay thế này chắc chắn tốt hơ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.