No se puede obtener correctamente .bashrc de un script de shell

51

Normalmente podemos obtener el ~/.bashrcarchivo fuente usando este comando

source ~/.bashrc

pero si escribo esto en un script de shell y lo ejecuto, no pasa nada. ¿Por qué?
¿Hay alguna forma de hacer esto?

Mi guión:

#!/bin/bash
chmod a+x ~/.bashrc
source ~/.bashrc

También probé .(punto) en lugar de source. Mismo resultado.

shantanu
fuente

Respuestas:

26

Un script de shell se ejecuta en su propia instancia de shell. Todas las configuraciones de variables, definiciones de funciones y demás solo afectan a esta instancia (y tal vez a sus hijos), pero no al shell de llamada, por lo que desaparecen una vez que finaliza el script.

Por el contrario, el sourcecomando no inicia una nueva instancia de shell, sino que usa el shell actual para que los cambios permanezcan.

Si desea un acceso directo para leer su .bashrc, use una función de shell o un alias en lugar de un script de shell, como

alias brc='source ~/.bashrc'
Florian Diesch
fuente
Gracias por su respuesta rápida. Su solución puede funcionar, pero tengo que editar el archivo bashrc manualmente para guardar la línea 'aliac brc = ....'. Estoy tratando de desarrollar una interfaz gráfica de usuario para cambiar la variable de entorno. Por lo tanto, no puedo editar el archivo bashrc de otra computadora manualmente.
shantanu
1
Debe ejecutar source ~/.bashrcen el shell en el que desea cambiar el entorno. No puede cambiarlo desde otro proceso. Tal vez (globalmente) agregar este alias podría ser parte del proceso de instalación de su GUI.
Florian Diesch
1
entonces, ¿pongo su comando alias anteriormente en el script y luego invoco brc cuando quiero obtener mi .bashrc o necesito poner ese comando alias en un archivo en algún lugar?
user137717
Lo que terminé haciendo es una extensión de la respuesta de Florian Diesch. Puede usar un alias de varias líneas: alias brc = 'chmod a + x ~ / .bashrc; source ~ / .bashrc 'Todavía soy bastante nuevo, así que no estoy seguro de si esto se considera' mala práctica '. Sin embargo, funciona.
A_user_aparece el
13

Su .bashrcgeneralmente comienza:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

Como su secuencia de comandos no tiene configurada la PS1 (porque no es interactiva), no restablece la ruta porque se cierra antes. Para demostrarlo, modifique su script:

    #!/bin/bash
    chmod a+x ~/.bashrc
    PS1='$ '
    source ~/.bashrc

Esto ahora permitirá que sus scripts funcionen con el nuevo .bashrc. Nota: una vez que se cierra el script, el entorno se establecerá en lo que era antes de comenzar el script. Los cambios se reflejarán la próxima vez que se inicie un terminal.

ravi nankani
fuente
Al menos desde 16.04 y probablemente antes, el Ubuntu predeterminado .bashrcusa una forma más confiable para verificar que el shell sea interactivo. /etc/bash.bashrcTodavía tiene la prueba de PS1.
Zanna
12

Tratar:

exec bash

Esto debería recargar ~ / .bashrc, ~ / .bash_aliases, etc.

Alin Andrei
fuente
99
Esto reemplaza el proceso actual de bash por uno nuevo. No es mucho más corto o más fácil que usarlo, sourcepero destruye cualquier variable y tal que el usuario haya configurado manualmente, lo que puede o no ser lo que desea.
Florian Diesch
espere, en el contexto de un script de Shell con otros comandos después del abastecimiento de bashrc, ¿coloca los comandos que necesitan el nuevo estado de bash después de eso exec bash, la forma en que entiendo que el comando después seguirá estando en la misma configuración de bash que antes?
tatsu
11

Quiero complementar la respuesta de ravi :

Este comportamiento es específico de Ubuntu (y probablemente de las distribuciones más derivadas), ya que su ~/.bashrcarchivo predeterminado comienza con un cortocircuito, Ubuntu 18.04, por ejemplo:

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

Eso detendrá la evaluación del archivo si se está ejecutando en un shell no interactivo, que es el caso de su script ya que todos los scripts se ejecutan en un shell no interactivo y, posteriormente, cada archivo sourceheredará esta propiedad.

eval cortar a tajos

Descubrí un truco feo para solucionar Ubuntu específicamente, usando en evallugar de source:

eval "$(cat ~/.bashrc | tail -n +10)"

Simplemente omite las pocas primeras líneas y evalúa el resto de las demás, de ~/.bashrcmodo que el resto se evalúa y modifica la ejecución actual.

Tenga en cuenta que es un número mágico y que podría no funcionar en las versiones de Ubuntu; pero puede ser una buena solución si está creando scripts para sistemas más o menos conocidos.

Una solución más elegante podría implicar el uso de expresiones regulares para apuntar a los bits específicos que detienen la evaluación.

Alternativa de Shebang

Otra alternativa que podría funcionar mejor en algunos escenarios es obligar al script a ejecutarse en un shell interactivo agregando una bandera en el shebang :

#!/bin/bash -i

Tenga en cuenta algunas cosas:

  • Es una mejor práctica usar el #!/usr/bin/env bashformulario, pero de esta manera no puede iniciar el shell con argumentos .
  • El uso de -itiene sus propias consecuencias, entre ellas, los programas solicitarán la interacción del usuario y esto generalmente no está destinado a los scripts, por ejemplo, la instalación de debpaquetes podría detener el script en las dpkg configureindicaciones .
  • Inicialmente intenté usar set -iy set +iactivar y desactivar la función donde la necesitaba, pero esto no funciona .
stefanmaric
fuente
2

Ninguno de los otros métodos funcionó para mí [ source /path/to/filevs . ./path/to/file, alias, etc ...], hasta que, gracias a este tutorial , descubrí que usando:

#!/usr/bin/env bash el asunto

en lugar del más simple, #!/usr/bin/envpermite que los argumentos pasen al intérprete, que creo que es la clave aquí; consulte este documento para obtener más información.

En cualquier caso, si los comandos de origen en cualquier forma no funcionan para usted, intente verificar su shebang, ese podría ser el problema :)

Nikksno
fuente