僅當該行尚未成為文件的一部分時才在文件中插入該行

僅當該行尚未成為文件的一部分時才在文件中插入該行

我正在尋找創建一個腳本來自動將一些自訂配置應用於基於文字的配置檔案。

在目前的情況下,我正在搜尋新增 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"
'

但我不推薦它。

相關內容