2015-03-19 39 views
5

Tôi đã đọc tất cả các câu hỏi tương tự về chủ đề này, nhưng không tìm thấy câu hỏi phù hợp với những gì tôi đang gặp phải. Tôi xin lỗi nếu điều này đã được trả lời rồi.sed không hoạt động từ bên trong tập lệnh bash

Bên trong một tập lệnh bash tôi đã viết, có một lệnh sed rất đơn giản, có vẻ như không hoạt động. Không có lỗi và lệnh hoạt động hoàn hảo khi chạy từ dòng lệnh.

Trong đầu ra từ bộ -x, tôi có thể thấy lệnh sed thực thi hoàn hảo.

GNU bash, phiên bản 4.3.11 (1) -release (x86_64-pc-linux-gnu)

Bash kịch bản: (giảm bớt cho sự hiểu biết dễ dàng hơn)

#!/bin/bash -x 

# This script has the exact same sed command as used on cli 

contact='"[email protected]"' 

sed -i "/$contact/d" /home/tim/Desktop/file.txt 

exit 

Shell đầu ra:

[email protected]:~/Desktop$ cat file.txt 
t,b,[email protected] 
[email protected]:~/Desktop$ ./test.sh 
+ contact='"[email protected]"' 
+ sed -i '/"[email protected]"/d' /home/tim/Desktop/file.txt 
+ exit 
[email protected]:~/Desktop$ cat file.txt 
t,b,[email protected] 
[email protected]:~/Desktop$ sed -i "/"[email protected]"/d" /home/tim/Desktop/file.txt 
[email protected]:~/Desktop$ cat file.txt 
[email protected]:~/Desktop$ 

Tôi cho rằng tôi đang thiếu một điều gì đó rất rõ ràng, nhưng tôi đã nhìn chằm chằm vào nó hy vọng câu trả lời sẽ nhảy ra khỏi màn hình và tát vào mặt tôi. Xin giúp :-)

Tim

+0

Tại sao bạn có 2 dấu ngoặc kép trong 'contact = '" [email protected] "''. Nó chỉ nên là: 'contact = 'tim @ email.com'' – anubhava

+0

Lệnh của bạn là _not_ giống hệt nhau: bên trong kịch bản bạn gửi kèm theo mẫu khớp với dấu nháy đơn, trên cli với các dấu ngoặc kép. Điều đó có nghĩa là, sed được gọi từ tập lệnh bash của bạn khớp với địa chỉ email được đính kèm trong dấu ngoặc kép, mà nó không có trong tệp của bạn. – collapsar

+0

@anubhava Xin lỗi, tôi nên đoán ai đó sẽ hỏi điều đó. Trong kịch bản dumbed xuống có vẻ như vô nghĩa, nhưng trong kịch bản thực tế có một chuỗi giải mã base64, sau đó openssl giải mã và trở thành biến số liên lạc $, và được trích dẫn. Tôi không muốn cố gắng loại bỏ các dấu ngoặc kép vì biến được sử dụng trong nhiều hàm khác mà sau đó sẽ phải được viết lại. Dù bằng cách nào, nó hoạt động trên dòng lệnh với dấu ngoặc kép. – asimovwasright

Trả lời

8

Có dấu ngoặc kép quanh mail trong biến $contact kịch bản đang thiếu từ cuộc gọi dòng lệnh:

# case 1 - works 
# only the sed pattern delimiters are enclosed in quotes and these quotes will be stripped by the shell. 
sed -i "/"[email protected]"/d" ./file.txt; cat file.txt 

# case 2 - fails 
# escaping with \ turns dquotes #2,3 from shell-level delimiters to char literals w/o special semantics. 
sed -i "/\"[email protected]\"/d" ./file.txt; cat file.txt 

# case 3 - fails 
# Single quotes enclose the complete sed pattern spec which comprises double quotes enclosing the mail address 
sed -i '/"[email protected]"/d' ./file.txt; cat file.txt 

# case 4 - works 
sed -i "/[email protected]/d" ./file.txt; cat file.txt 

# case 5 - works 
sed -i '/[email protected]/d' ./file.txt; cat file.txt 

này sẽ giải thích các hành vi khác nhau của kịch bản so với cuộc gọi cli.

OP chỉ ra rằng anh ta cần dấu ngoặc kép trong tập lệnh thực. Tuy nhiên, có thể vậy, nếu các dấu ngoặc kép này không có trong tệp, sẽ không có kết quả phù hợp.

Một giải pháp sẽ được xử lý trước các tập tin (nếu cần thiết, làm việc trên một bản sao) với sed:

sed -i 's/,/","/g; s/^/"/; s/$/"/' ./file.txt 

lệnh này giả định một danh sách bằng dấu phẩy của các mặt hàng trên mỗi dòng không có mục chứa dấu ngoặc kép . Nó sẽ bọc mỗi mục trong dấu ngoặc kép để chúng sẽ khớp với mẫu tìm kiếm trong biến số $contact của tập lệnh gốc.

Alternative (chuyển thể từ this SO answer [mà tôi đã không được tác giả của])

Một tùy chọn khác là thay đổi phần có liên quan của kịch bản được phát sinh một biến thứ hai từ $contact:

contact='"[email protected]"' 
c2=$(echo $contact | tr -d '"') 

sed -i "/$c2/d" /home/tim/Desktop/file.txt 
+0

Tại sao các dấu ngoặc kép bị tước bởi vỏ và thay thế bằng dấu nháy đơn? Nếu tôi có thể hiểu điều đó, tôi sẽ rất hạnh phúc :-) – asimovwasright

+1

Trích dẫn là một cơ chế chung để chỉ định các chuỗi ký tự chứa các ký tự có ngữ nghĩa đặc biệt cho bộ xử lý lệnh - ví dụ. khoảng trống. Các dấu nháy kép và đơn lẻ khác nhau (như một quy tắc chung) trong các dấu ngoặc kép đó vẫn cho phép mở rộng biến. Vì vậy, trong mọi trường hợp, sed không nhận được để xem cặp dấu ngoặc kép ngoài cùng.Trong cuộc gọi dòng lệnh của bạn, có _2_ cặp ngoài cùng và có hiệu quả 3 chuỗi liền kề được ngầm đưa vào một đối số duy nhất để sed (biểu thức mẫu). Tôi đã thêm trường hợp 2, tương phản với trường hợp 1,3. – collapsar

+0

Phải, đã hiểu và cảm ơn bạn đã giải thích rõ ràng! Tôi nghĩ rằng tôi sẽ phải sử dụng prepocessor của bạn để thay đổi các tiêu chuẩn trận đấu. Rất hữu ích :-) – asimovwasright

3

Đây chỉ là một bổ sung cho câu trả lời của collapsar đã giải quyết được vấn đề.

Khi chúng tôi sử dụng sed trong tập lệnh bash, tập lệnh bash đóng vai trò như một trình bao bọc đối với sed. Điều này có hai mục đích

  • lệnh sed có thể được thực hiện như thể nó được thực hiện bên ngoài bash.

  • Trình bao bọc tập lệnh bash giúp sed giao tiếp với thế giới bên ngoài , sử dụng các biến môi trường.

Ví dụ, giả sử rằng file testfile chứa hai dòng

[email protected] 
[email protected] 

Bây giờ Nếu tôi muốn viết một kịch bản bash giúp sed thay các dòng có chứa tim @ email .com tập lệnh của tôi sedscript sẽ như sau:

#!/bin/bash 
contact='[email protected]' 
sed -i "/$contact/d" $1 

Bây giờ tôi sẽ thực thi kịch bản như dưới đây

./sedscript testfile 

để loại bỏ tất cả các dòng có chứa [email protected].

Trong thực tế, bạn có thể thay thế $ 1 bằng tên tệp thực tế. Nhưng điểm quan trọng cần lưu ý, như đã đề cập trong câu trả lời trước, là bất cứ khi nào chúng ta sử dụng một biến bash bên trong lệnh sed, luôn luôn kèm theo lệnh trong dấu ngoặc kép. Chỉ sau đó bash sẽ thay thế biến bằng chuỗi tương ứng trước khi chuyển nó sang sed.

Các vấn đề liên quan