Intereting Posts

Каков наиболее сжатый способ вставки или обновления строки?

Я пишу много скриптов adhoc для добавления строк в sudoers, sysctl.conf и т. Д. Обычно я использую модуль lineinfile. Иногда, однако, я не могу этого сделать, поэтому я использую:

WHAT_I_WANT='my line of text = something' WHAT_TO_REPLACE='my line of text = .*' FILE_TO_EDIT=conf_file.conf if ( ! grep -q "^$WHAT_I_WANT\$" FILE_TO_EDIT ); then echo "$WHAT_I_WANT" >> FILE_TO_EDIT else sed -i "s/$WHAT_TO_REPLACE/$WHAT_I_WANT/g' FILE_TO_EDIT fi 

Я предполагаю, что есть более эффективный способ сделать это. В идеале, с одной строкой и одним языком (а также таким образом, который позволяет сопоставлять регулярные выражения, удалять прокомментированные строки и резервные копии файлов) Но я не знаю, что это такое.

  • Использование дополнительных длинных имен переменных для замены длинных строк является IMO контрпродуктивным.
  • Чтобы развернуть переменные в командах grep / sed, используйте двойные кавычки.
  • Использование подстановочных знаков .* В переменных присваивания будет выполняться расширение имени файла (globbing)
  • Следующий сценарий использует условное выполнение при успехе && или fail || вместо if.

 REPL='something' PATT='my line of text = ' FILE=conf_file.conf cat $FILE echo '=========' grep -q "^$PATT" $FILE && (sed -i "s/^$PATT.*$/$PATT$REPL/" $FILE) || (echo "$PATT$REPL" >> $FILE) cat $FILE - REPL='something' PATT='my line of text = ' FILE=conf_file.conf cat $FILE echo '=========' grep -q "^$PATT" $FILE && (sed -i "s/^$PATT.*$/$PATT$REPL/" $FILE) || (echo "$PATT$REPL" >> $FILE) cat $FILE 

На самом деле это не однострочный, но вы можете сделать это с помощью одного вызова sed :

 sed -e ' /pat/{s//repl/g;h;} $!b G s/\n..*//;t s/$/repl/ ' yourfile 

NB: Я специально использовал pat и repl для шаблона и замены соответственно, а не переменные оболочки, как вы это делали. В основном по двум основным причинам они будут мешать потоку sed-кода + для правильности мы должны процитировать и то, и другое, чтобы заставить их работать. Эта работа я оставляю вам.

Поток: скажем, в файле никогда не было / pat /, тогда все строки берутся в stdout командой $! B, а последняя строка, когда добавляется G, просто видит пустое удержание, поэтому t не выполняется, и у нас есть операция добавления ,

Когда мы видим a / pat / line, тогда это s /// – ed и область удержания отмечена. если это не последняя строка, мы просто выходим на stdout. Для eof мы выполняем проверку удержания и, поскольку она непустая (предполагается, что repl is NONEMPTY , тестовый путь будет выполнен после удаления трюма из пространства шаблонов.


Perl дает ясность, чтобы совместить намерение «слово в слово» в коде:

 perl -lne '$a += s/pat/repl/g,print}{print q[repl] unless $a' 

Для чтения: переменная $a служит счетчиком числа подстановок. В конце мы добавили бы к файлу, когда ранее не было никаких подписчиков.

А что касается предоставления информации о шаблоне / замене через переменные, мы можем это сделать:

 WHAT_I_WANT='my line of text = something' WHAT_TO_REPLACE='my line of text = .*' FILE_TO_EDIT=conf_file.conf perl -li -sn -e ' $a += s/$pat/$repl/g,print}{print $repl unless $a ' -- -pat="$WHAT_I_WANT" -repl="$WHAT_TO_REPLACE" -- "$FILE_TO_EDIT"