2013-11-28 8 views
25

Używam następujące polecenie sed zastąpić niektóre parametry w pliku konfiguracyjnym:Jak dodać wiersz w sed jeśli nie zostanie znaleziony

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

Teraz mam jeden problem. Jeśli linia nie istnieje, chcę dodać ją do dolnej części pliku.

Dzwonię to z popen z programu C. Próbowałem użyć awk.

Odpowiedz

41

Spróbuj tego:

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

Bardzo łatwe i użyteczne! – JohnyTex

1

Oto implementacja 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" 
} 

uruchomić go za pomocą

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

lub

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

EDIT: Jako jedną wkładką:

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

muszę przyczynę jeden liniowej wyślę to jako wezwanie systemu z c programowo. – Evilmachine

2

tutaj jest jeden awk-liner:

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

tego nie robi w miejscu zmiany w pliku, można jednak:

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

Używając sed, można powiedzieć:

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

To zastąpi parametr, jeśli istnieje, w przeciwnym razie doda go do dolnej części pliku.


Użyj opcji -i jeśli chcesz edytować plik w miejscu:

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

To nie wydaje się działać w ogóle. Dodaje "option = value" po każdym wierszu. Nie jestem pewna, jak to się stało, że zdobyły dwie karty upomnienia. Możesz zrobić "$ aoption = value", ale nie mogę tego uzależnić od poprzedniego, więc dołącza się do końca niezależnie. – sosiouxme

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

załadować wszystkie pliki w buforze, w końcu zmienić wszystko wystąpienie i jeśli bez zmian występuje, dodać na końcu

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

Jako awk-tylko jedną wkładką:

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] to twój wpis file. Jest on otwierany i zapisywany w pętli for bloku END. Otwarcie file dla wyjścia w bloku END zastępuje potrzebę użycia narzędzi, takich jak sponge lub zapisywanie do pliku tymczasowego, a następnie mv ing pliku tymczasowego do file.

Dwa przypisania do tablicy a[] kumulują wszystkie linie wyjściowe do a.if(!f)a[++n]=s dołącza nowy option=value, jeśli główna pętla awk nie może znaleźć option w file.

Dodałem kilka spacji (nie wiele) dla czytelności, ale naprawdę potrzebujesz tylko jednego miejsca w całym programie awk, przestrzeni po print. Jeśli file zawiera , zostaną one zachowane.

0

Opracowałem rozwiązanie grep/sed kev, ustawiając zmienne w celu zmniejszenia duplikacji.

Ustaw zmienne w pierwszym wierszu (wskazówka: $_option musi pasować do wszystkiego w linii, aż do wartości [łącznie z dowolnym seperatorem takim jak = lub:]).

 
_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"\ 
     ' 

uwadze, że sh -c '...' tylko ma wpływ na poszerzenie zakresu zmiennych bez konieczności stosowania export. (Patrz Setting an environment variable before a command in bash not working for second command in a pipe)

1

Oto seder jednoosobowy, który wykonuje pracę w linii. Zauważ, że zachowuje lokalizację zmiennej i jej wcięcie w pliku, jeśli istnieje. Jest to często ważne dla kontekstu, na przykład gdy pojawiają się komentarze lub gdy zmienna znajduje się w wciętym bloku. Każde rozwiązanie oparte na paradygmacie "usuń i dopisz" nie udaje się na tym źle.

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

Z ogólnej pary zmiennej/wartość można napisać to w następujący sposób:

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 

Wreszcie, jeśli chcesz również zachować inline komentarze, można to zrobić z połowu Grupa. Na przykład. jeśli test.conf zawiera następujące elementy:

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

Następnie uruchomiony ten

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

Produkuje że:

a=123 
# Here is "c": 
    c="yay" # with its own comment and indent 
b=234 
d=567 
Powiązane problemy