Вставка строки в файл только в том случае, если эта строка еще не является частью файла

Вставка строки в файл только в том случае, если эта строка еще не является частью файла

Я пытаюсь создать скрипт для автоматического применения некоторых пользовательских настроек к текстовым файлам конфигурации.

В данном случае я ищу возможность добавить 2 строки, /etc/sysctl.confесли этих строк еще нет в файле (чтобы избежать многократного появления этих строк в файле).

Вот скрипт, который я использую:

if [ `grep vm.swappiness /etc/sysctl.conf` != "vm.swappiness=5" ]; then
echo vm.vfs_cache_pressure=50 | sudo tee -a /etc/sysctl.conf
fi
if [ `grep vm.vfs_cache_pressure /etc/sysctl.conf` != "vm.vfs_cache_pressure=50" ]; then
echo vm.vfs_cache_pressure=50 | sudo tee -a /etc/sysctl.conf
fi

и вот какую ошибку я получаю:

/home/erwan/Workspace/Install.sh: ligne 19 : [: != : opérateur unaire attendu
/home/erwan/Workspace/Install.sh: ligne 23 : [: != : opérateur unaire attendu

Что я делаю не так?

решение1

Это проблема:

if [ `grep vm.swappiness /etc/sysctl.conf` != "vm.swappiness=5" ]; then

Поскольку if grepничего не находит, он ничего не выводит, и левая часть этого будет ничем, что является ошибкой. Это также проблема, если он что-то находит, поскольку вывод может содержать пробелы (например, if vm.swappinessвстречается в файле несколько раз). Это нужно заключить в кавычки, иначе при раскрытии это будет выглядеть как ряд отдельных строк.

Таким образом, вы должны использовать if [ "$(grep ...)" ]так, чтобы вывод был заключен в кавычки. Если вывод отсутствует, у вас есть "", что нормально с любой стороны теста в bash.

Однако в этом случае я бы рекомендовал использоватьстатус выходавместо grep. Из man grep:

СТАТУС ВЫХОДА

Обычно статус выхода равен 0, если выбранные строки найдены, и 1 в противном случае. Но статус выхода равен 2, если произошла ошибка...

Также полезен вот этот -qпереключатель:

-q, --тихий, --тихий

Тихо; ничего не писать в стандартный вывод. Выйти немедленнос нулевым статусомесли найдено какое-либо совпадение, даже если была обнаружена ошибка.

Итак, следует помнить $?о статусе завершения последнего завершенного процесса переднего плана:

grep -q grep vm.vfs_cache_pressure /etc/sysctl.conf
if [ $? -eq 1 ]; then

Это условие будет истинным, если grepничего не найдено и не произошло ошибки.

решение2

Это может быть потому, что ваш grepничего не возвращает. Поскольку он не заключен в кавычки, вы получаете это сообщение об ошибке (ожидается унарный оператор). Попробуйте:-

if [ "$(grep vm.swappiness /etc/sysctl.conf)" != "vm.swappiness=5" ]; then

решение3

Просто в целях вдохновения, возможно, потребуется некоторая доработка:

#assuming there is only one line with vm.swappiness
#otherwise you can use the test command with "grep -c vm.swappiness" first
#tests if the correct line is in the file
if grep -q -E '^vm.swappiness=5$' /etc/sysctl.conf; then
    echo "all good, do nothing";
else
    echo "removing possible lines with vm.swappiness"
    sudo sed -i '/^vm.swappiness=/d' /etc/sysctl.conf 
    echo "adding line with correct swappiness"
    sudo bash -c "echo 'vm.swappiness=5' >> /etc/sysctl.conf"
fi

Также может быть полезно обернуть это в функцию, чтобы можно было вызывать ее и со следующим параметром.

решение4

Вероятно, это сработает:

f=/etc/sysctl.conf
[ -w "$f" ] || exit 1
for line in 'vm.swappiness=5' 'vm.vfs_cache_pressure=50' ; do
    grep -q "$line" <"$f" || printf %s\\n "$line"
done >>"$f"

Вам, вероятно, следует выйти sudoиз этого сценария. Если необходимо, запустите сценарийс sudoнравится sudo ./script.shи сохраните его как отдельный модуль от других скриптов. В противном случае сделайте:

sudo sh -c '
    f=/etc/sysctl.conf
    [ -w "$f" ] || exit 1
    for line in "vm.swappiness=5" "vm.vfs_cache_pressure=50" ; do
        grep -q "$line" <"$f" || printf %s\\n "$line"
    done >>"$f"
'

Но я не рекомендую этого делать.

Связанный контент