仅当该行尚未成为文件的一部分时才在文件中插入该行

仅当该行尚未成为文件的一部分时才在文件中插入该行

我正在寻找创建一个脚本来自动将一些自定义配置应用于基于文本的配置文件。

在目前的情况下,我正在搜索添加 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

因为如果grep找不到任何东西,它不会输出任何东西,并且它的左边什么也不会,这是一个错误。如果它确实找到了某些东西,这也是一个问题,因为输出可能包含空格(例如,如果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"
'

但我不推荐它。

相关内容