Thay thế một chuỗi trong tập lệnh shell bằng một biến


93

Tôi đang sử dụng mã bên dưới để thay thế một chuỗi bên trong một tập lệnh shell.

echo $LINE | sed -e 's/12345678/"$replace"/g'

nhưng nó được thay thế bằng $replacethay vì giá trị của biến đó.

Ai có thể cho biết điều gì đã xảy ra?


Đối với câu hỏi liên quan phổ biến về việc xử lý các giá trị có dấu gạch chéo trong chúng, hãy xem stackoverflow.com/questions/5864146/use-slashes-in-sed-replace
tripleee,

Câu trả lời:


146

Nếu bạn muốn diễn giải $replace, bạn không nên sử dụng dấu ngoặc kép vì chúng ngăn cản việc thay thế biến.

Thử:

echo $LINE | sed -e "s/12345678/\"${replace}\"/g"

giả sử bạn muốn đặt dấu ngoặc kép. Nếu bạn không muốn dấu ngoặc kép, hãy sử dụng:

echo $LINE | sed -e "s/12345678/${replace}/g"

Bảng điểm:

pax> export replace=987654321
pax> echo X123456789X | sed "s/123456789/${replace}/"
X987654321X
pax> _

Chỉ cần cẩn thận để đảm bảo rằng ${replace}không có bất kỳ ký tự nào có ý nghĩa sed(chẳng /hạn như) vì nó sẽ gây nhầm lẫn trừ khi được thoát ra. Nhưng nếu, như bạn nói, bạn đang thay thế một số này bằng một số khác, thì đó không phải là vấn đề.


Tôi không muốn có dấu ngoặc kép đặt in.i muốn một số được thay thế bằng khác
Vijay

1
paxdiablo: setcũng không cần thiết (và bạn sẽ sử dụng nó như thế nào?). Chỉ là replace=987654321.
Roman Cheplyaka

Tôi thường sử dụng exportđể đảm bảo rằng các biến được đặt cho trẻ em nhưng, như bạn nói, bạn có thể dễ dàng tránh nó. Tuy nhiên, việc sử dụng hay không exportlà không liên quan ở đây (vấn đề về kiểu dáng) và không ảnh hưởng đến câu trả lời thực tế, đó là cách sử dụng các biến trong một sedlệnh.
paxdiablo

Giải pháp này dường như không hoạt động với -itùy chọn. Bạn có biết tại sao không? hoặc làm thế nào để làm cho nó hoạt động?
Gabriel

1
Cũng có thể chỉ ra rằng việc chuyển từ dấu ngoặc đơn sang dấu ngoặc kép yêu cầu bất kỳ $hoặc `trong sedtập lệnh phải được thoát bằng dấu gạch chéo ngược, để bảo vệ nó khỏi cơ chế thay thế của trình bao cho các chuỗi được trích dẫn kép.
tripleee

73

bạn có thể sử dụng shell (bash / ksh).

$ var="12345678abc"
$ replace="test"
$ echo ${var//12345678/$replace}
testabc

3
Có thể muốn đề cập đến điều đó dành riêng cho bash (và ksh?). Có lẽ không phù hợp với hầu hết mọi người nhưng một số người trong chúng ta vẫn buộc phải làm việc trên UNIXen cổ đại :-)
paxdiablo

6
Hãy cẩn thận, điều này cũng không thành công trên dấu gạch ngang, đó là /bin/shtrên nhiều Linux hiện đại.
phihag

26

Không dành riêng cho câu hỏi, nhưng dành cho những người cần cùng loại chức năng được mở rộng để rõ ràng hơn từ các câu trả lời trước:

# create some variables
str="someFileName.foo"
find=".foo"
replace=".bar"
# notice the the str isn't prefixed with $
#    this is just how this feature works :/
result=${str//$find/$replace}
echo $result    
# result is: someFileName.bar

str="someFileName.sally"
find=".foo"
replace=".bar"
result=${str//$find/$replace}
echo $result    
# result is: someFileName.sally because ".foo" was not found

8

Dấu ngoặc kép rất mạnh. Khi vào bên trong, bạn không thể làm gì để gọi thay thế biến, cho đến khi bạn rời đi. Sử dụng dấu ngoặc kép để thay thế:

echo $LINE | sed -e "s/12345678/$replace/g"


4
echo $LINE | sed -e 's/12345678/'$replace'/g'

bạn vẫn có thể sử dụng các dấu ngoặc kép, nhưng bạn phải "mở" chúng khi bạn muốn biến được mở rộng đúng chỗ. nếu không thì chuỗi được coi là "theo nghĩa đen" (như @paxdiablo đã nói đúng, câu trả lời của anh ấy cũng đúng)


Điều này có vấn đề là việc sử dụng $replacebên ngoài bất kỳ dấu ngoặc kép nào sẽ khiến trình bao thực hiện mã hóa khoảng trắng và mở rộng ký tự đại diện trên giá trị. Điều này có vẻ hoạt động với các giá trị đơn giản, nhưng có thể làm nổ tung đáng kể trên các chuỗi không đáng kể. Không sử dụng điều này trong mã sản xuất.
tripleee

2

Để cho phép shell của bạn mở rộng biến, bạn cần sử dụng dấu ngoặc kép như

sed -i "s#12345678#$replace#g" file.txt

Điều này sẽ bị phá vỡ nếu $replacechứa các sedký tự đặc biệt ( #, \). Nhưng bạn có thể xử lý trước $replaceđể trích dẫn chúng:

replace_quoted=$(printf '%s' "$replace" | sed 's/[#\]/\\\0/g')
sed -i "s#12345678#$replace_quoted#g" file.txt

0

Tôi đã có một yêu cầu tương tự cho điều này nhưng var thay thế của tôi chứa một ký hiệu và. Thoát khỏi ký hiệu và như thế này đã giải quyết được vấn đề của tôi:

replace="salt & pepper"
echo "pass the salt" | sed "s/salt/${replace/&/\&}/g"

-1

Sử dụng cái này thay thế

echo $LINE | sed -e 's/12345678/$replace/g'

điều này phù hợp với tôi chỉ đơn giản là xóa các dấu ngoặc kép


-2

Tôi thích sử dụng dấu ngoặc kép hơn, vì các quptes đơn rất mạnh khi chúng ta sử dụng chúng nếu không thể thay đổi bất cứ thứ gì bên trong nó hoặc có thể gọi nhóm thay thế biến.

vì vậy hãy sử dụng dấu ngoặc kép được cài sẵn.

echo $LINE | sed -e "s/12345678/$replace/g"

6
Điều này có gì khác với câu trả lời của Dave không?
devnull
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.