32

С одним входным файлом, который содержит только комментарии (начиная с #) и строки VARIABLE = значение, возможно ли заменить значение для одной переменной, если оно найдено, и, в противном случае, добавить пару в конец файла, если не найдено?

Мой текущий метод работает, удаляя его в первом проходе, затем добавляя его в конец файла во втором проходе, но этот метод портит порядок строк (и это также две разные команды):

sed -r "/^FOOBAR=.*$/d"      -i samefile &&
sed -r "$ a\FOOBAR=newvalue" -i samefile

Есть ли в любом случае, чтобы сделать это, т.е. поддерживать порядок строк в одной строке sed? Если какая-то другая утилита (awk, ...) сделает это, я возьму это на себя.

8 ответов8

28

Это на самом деле довольно просто с sed если соответствует строке просто скопировать его в h старого пространства , то s ubstitute значение.
На ли линию е изменения $ трюма и шаблон x т , то проверить , если последнее пусто. Если он не пустой, значит, замена уже сделана, так что ничего не поделать. Если оно пустое, это означает, что совпадение не найдено, поэтому замените пространство шаблона на требуемую переменную = значение, а затем добавьте к текущей строке в буфере удержания. Наконец, снова изменим x:

sed '/^FOOBAR=/{h;s/=.*/=newvalue/};${x;/^$/{s//FOOBAR=newvalue/;H};x}' infile

Выше приведен синтаксис gnu sed . Портативный:

sed '/^FOOBAR=/{
h
s/=.*/=newvalue/
}
${
x
/^$/{
s//FOOBAR=newvalue/
H
}
x
}' infile
18

Это, вероятно, может быть сокращено. Это не одна команда sed, и она также использует grep, но, похоже, это то, что вам нужно. Это одна строка, и она редактирует файл на месте (без временных файлов).

grep -q "^FOOBAR=" file && sed "s/^FOOBAR=.*/FOOBAR=newvalue/" -i file || 
    sed "$ a\FOOBAR=newvalue" -i file
10

Вот простой sed подход, так как я не нахожу sed hold space легко работать. Если вы чувствуете себя комфортно с hold space , использование подхода don_crissti дает дополнительную возможность сохранить что-либо из существующей строки, но это обычно очень редко.

При таком подходе вы просто печатаете все, кроме линии, которую хотите отбросить, а затем в конце добавляете замену.

sed -n -e '/^FOOBAR=/!p' -e '$aFOOBAR=newvalue' infile
3

Основываясь на других ответах, если вы хотите заменить значение переменной, если эта переменная присутствует в файле, и добавить его в конец файла, если его нет (это не то, что делают ваши опубликованные команды sed ), Вы можете попробовать это:

perl -ne '$c=1 if s/^FOOBAR=.*$/FOOBAR=newvalue/;  
             print; 
             END{print "FOBAR=newvalue" unless $c==1}' file > tmpfile && 
mv tmpfile file
1

В awk это немного проще, хотя "редактирование на месте" не происходит автоматически:

awk -v varname="FOOBAR" -v newval="newvalue" '
    BEGIN {FS = OFS = "="}
    $1 == varname {$2 = newval; found = 1}
    {print}
    END {if (! found) {print varname, newval}}
' file > tempfile &&
mv tempfile file
0

Просто используйте grep и echo для создания пустой записи:

grep -q '^FOOBAR=' somefile || echo 'FOOBAR=VALUE' >> somefile
sed -i 's/FOOBAR=.*$/FOOBAR=VALUE/' somefile 

Каждая строка сбрасывается с нулевым кодом ошибки.

0

На самом деле работает следующим образом : sed -i '/^FOOBAR=/{h;s/=.*/=newvalue/};${x;/^$/{s//FOOBAR=newvalue/;H};x}' infile В ответе выбрано -i отсутствует.

-1

чтобы сделать это с Perl и на месте это прекрасно работает для меня:

grep ^FOOBAR= my.file && perl -i -ple "s/^FOOBAR=.+/FOOBAR=newvalue/g" my.file || echo FOOBAR=newvalue >> my.file

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .