2013-11-28 15 views
25

Tôi đang sử dụng sed lệnh sau đây để thay thế một số thông số trong một tập tin cấu hình:Làm thế nào để thêm một dòng trong sed nếu không hợp được tìm thấy

sed -i 's/^option.*/option=value/g' /etc/fdm_monitor.conf 

Bây giờ tôi có một vấn đề. Nếu dòng không tồn tại, tôi muốn thêm nó vào dưới cùng của tập tin.

Tôi đang gọi số này là popen trong chương trình C. Tôi đã thử sử dụng awk.

Trả lời

41

Hãy thử điều này:

grep -q '^option' file && sed -i 's/^option.*/option=value/' file || echo 'option=value' >> file 
+0

Rất dễ dàng và hữu ích! – JohnyTex

1

Dưới đây là một thực hiện awk

/^option *=/ { 
    print "option=value"; # print this instead of the original line 
    done=1;    # set a flag, that the line was found 
    next     # all done for this line 
} 
{print}     # all other lines -> print them 
END {     # end of file 
    if(done != 1)   # haven't found /option=/ -> add it at the end of output 
    print "option=value" 
} 

Run nó bằng cách sử

awk -f update.awk </etc/fdm_monitor.conf> /etc/fdm_monitor.conf.tmp && \ 
    mv /etc/fdm_monitor.conf.tmp /etc/fdm_monitor.conf 

hoặc

awk -f update.awk < /etc/fdm_monitor.conf | sponge /etc/fdm_monitor.conf 

EDIT: Là một one-liner:

awk '/^option *=/ {print "option=value";d=1;next}{print}END{if(d!=1)print "option=value"}' /etc/fdm_monitor.conf | sponge /etc/fdm_monitor.conf 
+0

Tôi cần một nguyên nhân một liner tôi gửi thông điệp này như một cuộc gọi hệ thống từ một programm c. – Evilmachine

2

đây là một awk một liner:

awk -v s="option=value" '/^option/{f=1;$0=s}7;END{if(!f)print s}' file 

này không làm tại chỗ thay đổi vào file, tuy nhiên bạn có thể:

awk '...' file > tmpfile && mv tmpfile file 
3

Sử dụng sed, bạn có thể nói:

sed -e '/option=/{s/.*/option=value/;:a;n;:ba;q}' -e 'aoption=value' filename 

Điều này sẽ thay thế thông số nếu nó tồn tại, nếu không sẽ thêm thông số vào cuối tệp.


Sử dụng tùy chọn -i nếu bạn muốn chỉnh sửa các tập tin tại chỗ:

sed -i -e '/option=/{s/.*/option=value/;:a;n;:ba;q}' -e 'aoption=value' filename 
+3

Điều này dường như không hoạt động chút nào. Nó thêm "option = value" sau mỗi dòng. Không chắc làm thế nào nó có hai upvotes. Bạn có thể làm '$ aoption = value' nhưng tôi dường như không thể làm điều đó có điều kiện trong trận đấu trước đó nên nó chỉ gắn vào cuối bất kể. – sosiouxme

1
sed -i '1 h 
1 !H 
$ { 
    x 
    s/^option.*/option=value/g 
    t 
    s/$/\ 
option=value/ 
    }' /etc/fdm_monitor.conf 

tải tất cả các tập tin trong bộ đệm, ở cuối, thay đổi tất cả điều xảy ra và nếu không có sự thay đổi xảy ra, thêm vào cuối

2
sed -i 's/^option.*/option=value/g' /etc/fdm_monitor.conf 
grep -q "option=value" /etc/fdm_monitor.conf || echo "option=value" >> /etc/fdm_monitor.conf 
3

Là một lớp lót chỉ awk:

awk -v s=option=value '/^option=/{$0=s;f=1} {a[++n]=$0} END{if(!f)a[++n]=s;for(i=1;i<=n;i++)print a[i]>ARGV[1]}' file 

ARGV [1] là thông tin bạn nhập file. Nó được mở và ghi vào trong vòng for của khối END. Mở file cho đầu ra trong khối END thay thế nhu cầu cho các tiện ích như sponge hoặc ghi vào một tệp tạm thời và sau đó mv nhập tệp tạm thời vào file.

Hai bài tập cho mảng a[] tích lũy tất cả các dòng đầu ra thành a.if(!f)a[++n]=s gắn thêm option=value mới nếu vòng lặp chính không thể tìm thấy option trong file.

Tôi đã thêm một số khoảng trống (không nhiều) để dễ đọc, nhưng bạn thực sự chỉ cần một không gian trong toàn bộ chương trình dự phòng, không gian sau print. Nếu file bao gồm # comments chúng sẽ được giữ nguyên.

0

Tôi đã xây dựng giải pháp grep/sed của kev bằng cách đặt biến để giảm trùng lặp.

Đặt biến trong dòng đầu tiên (gợi ý: $_option phải khớp với mọi thứ trên dòng cho đến khi giá trị [bao gồm bất kỳ seperator nào = hoặc:]).

 
_file="/etc/ssmtp/ssmtp.conf" _option="mailhub=" _value="my.domain.tld" \ 
     sh -c '\ 
      grep -q "^$_option" "$_file" \ 
      && sed -i "s/^$_option.*/$_option$_value/" "$_file" \ 
      || echo "$_option$_value" >> "$_file"\ 
     ' 

tâm rằng sh -c '...' chỉ có tác dụng mở rộng phạm vi của các biến mà không cần một export. (Xem Setting an environment variable before a command in bash not working for second command in a pipe)

1

Đây là một sed lót một lớp làm công việc nội tuyến. Lưu ý rằng nó giữ vị trí của biến và thụt đầu dòng trong tệp khi nó tồn tại. Điều này thường quan trọng đối với ngữ cảnh, như khi có các nhận xét xung quanh hoặc khi biến nằm trong một khối thụt lề. Bất kỳ giải pháp dựa trên mô hình "xóa-sau đó-chắp thêm" không thành công nghiêm trọng ở đây.

sed -i '/^[ \t]*option=/{h;s/=.*/=value/};${x;/^$/{s//option=value/;H};x}' test.conf 

Với một cặp chung của biến/giá trị mà bạn có thể viết nó theo cách này:

var=c 
    val='12 34' # it handles spaces nicely btw 
    sed -i '/^[ \t]*'"$var"'=/{h;s/=.*/='"$val"'/};${x;/^$/{s//c='"$val"'/;H};x}' test.conf 

Cuối cùng, nếu bạn cũng muốn giữ ý kiến ​​nội tuyến, bạn có thể làm điều đó với một nắm bắt nhóm. Ví dụ. nếu test.conf chứa sau:

a=123 
# Here is "c": 
    c=999 # with its own comment and indent 
b=234 
d=567 

Sau đó chạy này

var='c' 
val='"yay"' 
sed -i '/^[ \t]*'"$var"'=/{h;s/=[^#]*\(.*\)/='"$val"'\1/;s/'"$val"'#/'"$val"' #/};${x;/^$/{s//'"$var"'='"$val"'/;H};x}' test.conf 

Tạo rằng:

a=123 
# Here is "c": 
    c="yay" # with its own comment and indent 
b=234 
d=567 
Các vấn đề liên quan