Insertar una línea en un archivo solo si esta línea aún no forma parte del archivo

Insertar una línea en un archivo solo si esta línea aún no forma parte del archivo

Estoy buscando crear un script para aplicar automáticamente alguna configuración personalizada a archivos de configuración basados ​​en texto.

En el presente caso, estoy buscando agregar 2 líneas /etc/sysctl.confsi estas líneas aún no están en el archivo (para evitar que estas líneas aparezcan varias veces en el archivo).

Aquí está el script que uso:

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

y el error me sale:

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

¿Qué estoy haciendo mal?

Respuesta1

Esto es un problema:

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

Dado que si grepno encuentra nada, no genera nada, y el lado izquierdo de esto no será nada, lo cual es un error. También es un problema si encuentra algo, ya que la salida podría contener espacios en blanco (por ejemplo, si vm.swappinessestá en el archivo varias veces). Es necesario citarlo o aparecerá como una serie de cadenas distintas cuando se expanda.

Por lo tanto, debe utilizarlo if [ "$(grep ...)" ]para que se cite el resultado. Si no hay salida, tiene "", lo cual está bien en cualquier lado de una prueba en bash.

Sin embargo, en este caso recomendaría usar elestado de salidade grep en su lugar. De man grep:

ESTADO DE SALIDA

Normalmente, el estado de salida es 0 si se encuentran las líneas seleccionadas y 1 en caso contrario. Pero el estado de salida es 2 si ocurrió un error...

También es útil aquí el -qinterruptor:

-q, --tranquilo, --silencioso

Tranquilo; no escriba nada en la salida estándar. Salir inmediatamentecon estado cerosi se encuentra alguna coincidencia, incluso si se detectó un error.

Entonces, tenga en cuenta $?el estado de salida del último proceso en primer plano completado:

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

Esta condición será verdadera si grepno se encontró nada y no se produjo ningún error.

Respuesta2

Podría ser porque grepno devuelves nada. Como no está citado, aparece ese mensaje de error (se espera un operador unario). Intentar:-

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

Respuesta3

Solo con fines inspiradores, tal vez necesite algunos ajustes:

#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

También podría ser bueno incluir esto en una función, por lo que también puedes llamarlo con el siguiente parámetro.

Respuesta4

Probablemente esto funcione:

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"

Probablemente también deberías salirte sudode ese guión. Si es necesario, ejecute el script.con sudoMe gusta sudo ./script.shy manténgalo como un módulo separado de otros scripts. De lo contrario hazlo:

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

Pero no lo recomiendo.

información relacionada