Thay thế một nhân vật bằng một nhân vật khác trong Bash


223

Tôi cần có thể làm là thay thế một khoảng trắng ( ) bằng dấu chấm ( .) trong chuỗi trong bash.

Tôi nghĩ rằng điều này sẽ khá đơn giản, nhưng tôi là người mới nên tôi không thể tìm ra cách sửa đổi một ví dụ tương tự cho việc sử dụng này.

Câu trả lời:


390

Sử dụng thay thế chuỗi vỏ nội tuyến. Thí dụ:

foo="  "

# replace first blank only
bar=${foo/ /.}

# replace all blanks
bar=${foo// /.}

Xem http://tldp.org/LDP/abs/html/opes-manipulation.html để biết thêm chi tiết.


1
Mặc dù giải pháp này là tốt khi xử lý các chuỗi ngắn (trường hợp phổ biến, tôi đoán) người ta có thể thích trcác chuỗi dài. Trên hệ thống của tôi trvượt trội hơn bash bắt đầu từ các chuỗi có nhiều hơn 1000ký tự. Có vẻ như độ phức tạp thời gian của bash còn tệ hơn tuyến tính. Một thử nghiệm nhỏ : x="$(tr -dc 'a-z \n' </dev/urandom | head -c1M)"; time y="$(tr ' ' \\- <<< "$x")"; time z="${x// /-}". Với độ dài chuỗi là 1M (= 2 ^ 20) trđã lấy 0.04svà bash 5.0.11 đã lấy 17s. Với 2M trđã lấy 0.07s(dự kiến) nhưng bash mất 69s(gấp 4 lần chiều dài chuỗi gấp đôi).
Socowi

@Socowi Chơi với 1Mb được lưu trữ trong một biến không thực sự bình thường! Lên đến hơn 10Kb, bash dường như nhanh hơn so với việc sử dụng tr! ... Tùy thuộc vào bộ nhớ khả dụng và tài nguyên hw ... Nhưng bạn đã đúng!: Tùy thuộc vào loại công việc cần làm, các công cụ chuyên dụng sẽ hiệu quả hơn!
F. Hauri

Đối với các ký tự thoát như dòng mới, hãy đảm bảo tìm kiếm$'\n'
user2561747

75

Bạn có thể sử dụng tr, như thế này:

tr " " .

Thí dụ:

# echo "hello world" | tr " " .
hello.world

Từ man tr:

MÔ TẢ
     Dịch, ép và / hoặc xóa các ký tự từ đầu vào tiêu chuẩn, ghi vào đầu ra tiêu chuẩn.


Mặc dù câu hỏi này hoạt động cho câu hỏi như đã được hỏi, nhưng nó ít chung chung hơn câu trả lời được chấp nhận (hoạt động thay thế ký tự và cả chuỗi tùy ý), và nó cũng liên quan đến và lệnh bên ngoài.
Dan Dascalescu

2
Mặt khác, nó hoạt động trên một tệp 2gb mà không tải toàn bộ vào bộ nhớ.
aioobe

Câu hỏi là về "một chuỗi trong bash", không phải các tệp lớn tùy ý.
Dan Dascalescu

52

Trong bash, bạn có thể thực hiện thay thế mẫu trong một chuỗi với ${VARIABLE//PATTERN/REPLACEMENT}cấu trúc. Sử dụng chỉ /và không //thay thế chỉ xảy ra lần đầu tiên. Mẫu này là một mẫu ký tự đại diện, giống như các tập tin.

string='foo bar qux'
one="${string/ /.}"     # sets one to 'foo.bar qux'
all="${string// /.}"    # sets all to 'foo.bar.qux'



4

Hãy thử điều này cho các đường dẫn:

echo \"hello world\"|sed 's/ /+/g'|sed 's/+/\/g'|sed 's/\"//g'

Nó thay thế khoảng trắng bên trong chuỗi trích dẫn kép bằng một +tiếng hát, sau đó thay thế +dấu hiệu bằng dấu gạch chéo ngược, sau đó xóa / thay thế dấu ngoặc kép.

Tôi đã phải sử dụng điều này để thay thế các không gian trong một trong những con đường của tôi ở Cygwin.

echo \"$(cygpath -u $JAVA_HOME)\"|sed 's/ /+/g'|sed 's/+/\\/g'|sed 's/\"//g'

2
Đã có một câu trả lời hai năm tuổi giải quyết vấn đề sed. Các trích dẫn là không liên quan.
chepner
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.