Einfügen einer Zeile in eine Datei nur, wenn diese Zeile noch nicht Teil der Datei ist

Einfügen einer Zeile in eine Datei nur, wenn diese Zeile noch nicht Teil der Datei ist

Ich möchte ein Skript erstellen, um einige benutzerdefinierte Konfigurationen automatisch auf textbasierte Konfigurationsdateien anzuwenden.

Im vorliegenden Fall versuche ich, zwei Zeilen hinzuzufügen, /etc/sysctl.conffalls diese Zeilen noch nicht in der Datei vorhanden sind (um ein mehrfaches Vorkommen dieser Zeilen in der Datei zu vermeiden).

hier ist das Skript, das ich verwende:

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

und der Fehler, den ich bekomme:

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

Was mache ich falsch?

Antwort1

Das ist ein Problem:

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

Da „if grep“ nichts findet, wird auch nichts ausgegeben und die linke Seite enthält nichts, was ein Fehler ist. Es ist auch ein Problem, wenn etwas gefunden wird, da die Ausgabe Leerzeichen enthalten könnte (z. B. wenn „if“ vm.swappinessmehrfach in der Datei vorkommt). Diese müssen in Anführungszeichen gesetzt werden, sonst wird es beim Erweitern als eine Reihe unterschiedlicher Zeichenfolgen angezeigt.

Sie sollten daher verwenden, if [ "$(grep ...)" ]damit die Ausgabe in Anführungszeichen steht. Wenn keine Ausgabe erfolgt, haben Sie "", was auf beiden Seiten eines Tests in Bash in Ordnung ist.

In diesem Fall empfehle ich jedoch die Verwendung vonBeendigungsstatusvon grep stattdessen. Von man grep:

Beendigungsstatus

Normalerweise ist der Beendigungsstatus 0, wenn die ausgewählten Zeilen gefunden wurden, und andernfalls 1. Der Beendigungsstatus ist jedoch 2, wenn ein Fehler aufgetreten ist ...

Auch nützlich ist hier der -qSchalter:

-q, --quiet, --silent

Leise; schreibt nichts in die Standardausgabe. Beendet sofortmit Nullstatuswenn eine Übereinstimmung gefunden wird, auch wenn ein Fehler erkannt wurde.

Beachten Sie daher $?den Beendigungsstatus des letzten abgeschlossenen Vordergrundprozesses:

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

Diese Bedingung ist erfüllt, wenn grepnichts gefunden wurde und kein Fehler aufgetreten ist.

Antwort2

Es könnte daran liegen, dass Ihr grepnichts zurückgibt. Da es nicht zitiert ist, erhalten Sie diese Fehlermeldung (unärer Operator erwartet). Versuchen Sie:-

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

Antwort3

Nur zur Inspiration, muss vielleicht noch etwas optimiert werden:

#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

Es könnte auch sinnvoll sein, dies in eine Funktion einzubinden, sodass Sie diese auch mit Ihrem nächsten Parameter aufrufen können.

Antwort4

Das würde wahrscheinlich funktionieren:

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"

Sie sollten sudodieses Skript wahrscheinlich auch beenden. Führen Sie bei Bedarf das Skript ausmit sudosudo ./script.shund behalte es als separates Modul von anderen Skripten. Andernfalls mache :

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"
'

Aber ich empfehle es nicht.

verwandte Informationen