2016-06-14 46 views
5

如何使用bash的sed的命令更改此字符串:如何使用sed替換多行字符串?

<Directory /var/www/> 
    Options Indexes FollowSymLinks 
    AllowOverride None 
    Require all granted 
</Directory> 

到下面的字符串? (只改變串3號線)

<Directory /var/www/> 
    Options Indexes FollowSymLinks 
    AllowOverride All 
    Require all granted 
</Directory> 

注1:我不只是要定位的字符串「的AllowOverride無」,因爲還有其他的文件中出現不應該被改變。我需要針對整個字符串開始<Directory /var/www>

注2:我也需要覆蓋該文件。所以,在你的答案中考慮到這一點。以防萬一,爲GNU /非GNU版本的sed提供不同的版本。

+1

如果有一個更通用的[mcve]來查看什麼是常量,哪些不是:是否必須在'/ var/www'上?另外,使用'sed'作爲多行似乎不是最乾淨的方式:'awk'可以更好地處理這種方式。 – fedorqui

回答

0

我知道這是不是你所說的,也許它的價值不是用SED問?

python解決方案如何?它將作爲第一個參數傳遞給目錄的目錄移動到,正好代替<Directory元素,而您只寫None更改爲All並將更改寫回文件。它還可以在保留原始縮進的同時使用不同的縮進級別。適用於python2和python3。

畢竟我假設如果你有sed你可能也有python。

#!/usr/bin/env python 
import re 

r = re.compile(r'(<Directory /var/www/>\s+Options Indexes FollowSymLinks\s+AllowOverride)None(\s+Require all granted\s+</Directory>)', re.MULTILINE) 

for root, dirs, files in os.walk(sys.argv[1]): 
    for file_name in files: 
     if file_name.endswith('.conf'): 
      file_path = os.path.join(root, file_name) 
      with open(file_path) as fp: 
       data = r.sub(r'\1All\2', fp.read()) 
      with open(file_path, 'w+') as fp: 
       fp.write(data) 
7

由於圖案包含斜線,因此請使用\%(對於任何字符%)來標記搜索圖案。然後使用:

sed -e '\%^<Directory /var/www/>%,\%^</Directory>% s/AllowOverride None/AllowOverride All/' 

搜索模式內\%…%限制搜索到的匹配圖案之間的線,並且{ s/…/…/; }查找範圍內的所期望的圖案,並且使適當更換。

如果您不想將其限制爲單個目錄部分,而是限制爲所有目錄部分,請適當調整啓動模式。例如,這將匹配任何<Directory>部分:

sed -e '\%^<Directory [^>]*>%,\%^</Directory>% s/AllowOverride None/AllowOverride All/' 

你可以使它更具有選擇性根據您的要求。

+0

我不認爲OP旨在限制替換爲一個** **部分(但是所有** <目錄...> **部分)。除此之外,我認爲這個解決方案仍然會取代(第一個)** **和** **標記的最後一次出現之間的所有** ** AllowOverride None **。 – Leon

+0

@Leon:如果目錄名稱無關緊要,請將其從搜索範圍中的第一個模式中刪除。否:它將單獨處理每個「'到''範圍;它不會使用第一個「'作爲單個範圍。 –

+0

是的,你是對的。我在我的初始版本中有一個拼寫錯誤,試圖這樣做! – Leon

3

簡單的版本,依靠的AllowOverride線兩線內的後<目錄...>和使用GNU sed的延伸,是這樣的:

sed '/^<Directory/,+2 { s/AllowOverride None/AllowOverride All/g; }' 

UPDATE:這裏是不依賴於任何GNU擴展的版本(我先試了一下,但是發了一個錯字,很驚訝它沒有用,這就是爲什麼先發布其他版本的原因):

sed '/^<Directory/,/^<\/Directory>/ { s/AllowOverride None/AllowOverride All/; }' 
1

利用GNU桑達:

sed -zie 's!\(<Directory /var/www/>[^<]*AllowOverride\) None!\1 All!' ex1.txt 
  • 選項-z是空隔開的記錄:所有的文件是一個記錄, 所以只是做一個簡單的替換。
  • [^<]*(多行)正則表達式尊重目錄邊界,並允許靈活的格式和順序。
1

你的問題是口頭禪的好例子,不要用sed。真的,你不應該使用任何正則表達式引擎來實現上下文無關的語言,比如XML。但你可以接近,也許夠接近,awk

#! /usr/bin/awk -f 

/<Directory \/var\/www\/>/ { 
    line = NR 
} 

/ AllowOverride None/ && line + 2 == NR { 
    gsub(/None/, "All") 
} 

{ print } 

這樣,你沒有任何花哨,非標準正則表達式來閱讀,你的代碼表示,正是它的意思是:如果你發現了「目錄」行之後有「AllowOverride」 2號線,取代它。上面的正則表達式非常簡單(和Posix兼容),並且可以與任何版本的awk一起工作。

0

您的回答已經由user提供,只是check here

一些參考

在sed的最簡單的調用,它在模式空間,即一行文本。來自輸入的1行\ n分隔文本。模式空間中的單行沒有\ n ...這就是爲什麼你的正則表達式沒有找到任何東西。

您可以在模式空間中讀取多行,並且操作起來令人驚訝,但使用超過正常的努力.. Sed有一組允許這種類型的命令的命令...這是一個指向sed的命令摘要。這是我找到的最好的一個,讓我滾動。

但是,一旦開始使用sed的微指令,忘記了「單行」的想法。將它像結構化程序一樣佈置,直到你感覺到它爲止是非常有用的......它非常簡單,同樣很不尋常。您可以將其視爲文本編輯的「彙編語言」。簡介:使用sed來做簡單的事情,也許更多一些,但是總的來說,當它超出單行使用時,大多數人更喜歡別的東西... 我會讓別人建議別的東西..我真的不知道什麼是最好的選擇將是(我會用sed,但那是因爲我不知道perl的不夠好。)

sed '/^a test$/{ 
     $!{ N  # append the next line when not on the last line 
     s/^a test\nPlease do not$/not a test\nBe/ 
        # now test for a successful substitution, otherwise 
        #+ unpaired "a test" lines would be mis-handled 
     t sub-yes # branch_on_substitute (goto label :sub-yes) 
     :sub-not # a label (not essential; here to self document) 
        # if no substituion, print only the first line 
     P   # pattern_first_line_print 
     D   # pattern_ltrunc(line+nl)_top/cycle 
     :sub-yes # a label (the goto target of the 't' branch) 
        # fall through to final auto-pattern_print (2 lines) 
     }  
    }' alpha.txt 

這是同一個腳本,凝結成顯然難以閱讀和處理,但有些人會把這種可疑的稱爲單線式

sed '/^a test$/{$!{N;s/^a test\nPlease do not$/not a test\nBe/;ty;P;D;:y}}' alpha.txt 

這是我的命令「作弊表」

: # label 
= # line_number 
a # append_text_to_stdout_after_flush 
b # branch_unconditional    
c # range_change      
d # pattern_delete_top/cycle   
D # pattern_ltrunc(line+nl)_top/cycle 
g # pattern=hold      
G # pattern+=nl+hold     
h # hold=pattern      
H # hold+=nl+pattern     
i # insert_text_to_stdout_now   
l # pattern_list      
n # pattern_flush=nextline_continue 
N # pattern+=nl+nextline    
p # pattern_print      
P # pattern_first_line_print   
q # flush_quit       
r # append_file_to_stdout_after_flush 
s # substitute           
t # branch_on_substitute    
w # append_pattern_to_file_now   
x # swap_pattern_and_hold    
y # transform_chars