2011-08-19 17 views
31

Esto debe ser realmente simple o realmente complejo, pero no pude encontrar nada al respecto ... Estoy intentando abrir una nueva instancia de bash luego ejecute algunos comandos dentro de él y devuelva el control al usuario dentro de esa misma instancia.Invoque bash, ejecute comandos dentro de un shell nuevo y luego devuelva el control al usuario

me trataron:

$ bash -lic "some_command" 

pero esto ejecuta some_command dentro de la nueva instancia, a continuación, lo cierra. Quiero que permanezca abierto.

Un detalle más que podría afectar las respuestas: si puedo hacer que esto funcione, lo usaré en mi .bashrc como alias (es), ¡así que los puntos de bonificación para una implementación de alias!

+0

no entiendo la última parte acerca de los alias. Los alias se ejecutan en el contexto del shell actual, por lo que no tienen el problema que está pidiendo que se haya resuelto (aunque por lo general, las funciones son mejores que los alias, por varias razones). – tripleee

+0

Quiero ser capaz de poner algo como 'alias shortcut = 'bash -lic" some_command "'' en mi .bashrc luego ejecutar 'shortcut' y tener un nuevo shell con' some_command' ya ejecutado en él. –

Respuesta

18
+0

Intenté hacer esto en Windows 10 (tratando de escribir un archivo/script de inicio de proceso por lotes), y obtengo 'El sistema no puede encontrar el archivo especificado. – Scott

+1

@Scott lo depura paso por paso: 1) Does' cat ~/.bashrc' trabajo? 2) ¿Funciona 'cat <(echo a)'? 3) ¿Funciona 'bash --rcfile somefile'? –

+1

@Scott acabamos de toparnos con este problema en WSL (iniciando bash desde un archivo de lotes de inicio). Nuestra solución fue escapar de algunos de los caracteres para que el lote pudiera entenderlo: 'bash.exe --rcfile^<^ (echo 'source $ HOME/.bashrc; ls; pwd' ^)' debería ejecutarse desde el símbolo del sistema de Windows. – user2561747

2

Puede obtener la funcionalidad que desea obteniendo el script en lugar de ejecutarlo. por ejemplo:

 
$cat script 
cmd1 
cmd2 
$ . script 
$ at this point cmd1 and cmd2 have been run inside this shell 
+0

Hmm. Eso funciona, pero ¿no hay forma de incrustar todo en un 'alias = '''? –

+1

Nunca use alias; use funciones en su lugar. Puede poner: 'foo() {cmd1; cmd2; } 'dentro de los scripts de inicio, y luego ejecutando foo ejecutará los dos comandos en el shell actual. Tenga en cuenta que ninguna de estas soluciones le da un nuevo shell, pero puede hacer 'exec bash' y luego 'foo' –

+1

Nunca decir nunca. los alias tienen su lugar –

4

Puede pasar --rcfile para golpear para hacer que se lee un archivo de su elección. Se leerá este archivo en lugar de .bashrc. (Si eso es un problema, fuente ~/.bashrc desde el otro guión.)

Editar: lo tanto, una función para iniciar una nueva cáscara con las cosas de ~/.more.sh sería algo como:

more() { bash --rcfile ~/.more.sh ; } 

... y en .more.sh tendrías los comandos que deseas ejecutar cuando se inicie el shell. (Supongo que sería elegante evitar un archivo de inicio separado; no puede usar la entrada estándar porque entonces el shell no será interactivo, pero podría crear un archivo de inicio desde un documento aquí en una ubicación temporal, y luego leerlo).

27

Esta es una respuesta tardía, pero tuve exactamente el mismo problema y google me envió a esta página, por lo que para completar aquí es cómo solucionó el problema.

Por lo que yo sé, bash no tiene la opción de hacer lo que el póster original quería hacer. La opción -c siempre regresará después de que se hayan ejecutado los comandos.

solución Roto: el intento más simple y evidente de evitar esto es:

bash -c 'XXXX ; bash' 

Esto funciona en parte (aunque con una capa de sub-shell extra). Sin embargo, el problema es que mientras un subconjunto heredará las variables de entorno exportadas, los alias y las funciones no se heredan. Entonces esto podría funcionar para algunas personas pero no es una solución general.

Mejor: la forma de evitar esto es crear dinámicamente un archivo de inicio y llame fiesta con este nuevo archivo de inicialización, asegurándose de que su nuevo archivo init llama a su normal/.bashrc si ~ necesario.

# Create a temporary file 
TMPFILE=$(mktemp) 

# Add stuff to the temporary file 
echo "source ~/.bashrc" > $TMPFILE 
echo "<other commands>" >> $TMPFILE 
echo "rm -f $TMPFILE" >> $TMPFILE 

# Start the new bash shell 
bash --rcfile $TMPFILE 

Lo bueno es que el archivo init temporal se borrará solo en cuanto se lo utilice, reduciendo el riesgo de que no se limpie correctamente.

Nota: No estoy seguro de si/etc/bashrc se suele llamar como parte de un shell normal que no es de inicio de sesión.Si es así, es posible que desee obtener el archivo/etc/bashrc, así como su ~/.bashrc.

+0

La cosa 'rm -f $ TMPFILE' lo hace. Realmente no recuerdo el caso de uso que tuve para esto, y ahora uso técnicas de automatización más avanzadas, ¡pero este es el camino a seguir! –

+5

No hay archivos tmp con sustitución de proceso 'bash --rcfile <(echo". ~/.bashrc; a = b ")' –

+0

El archivo temporal solo se limpiará si el script Bash se ejecuta correctamente. Una solución más robusta sería usar 'trap'. – tripleee

1

Anexar al ~/.bashrc una sección como esta:

if [ "$subshell" = 'true' ] 
then 
    # commands to execute only on a subshell 
    date 
fi 
alias sub='subshell=true bash' 

, entonces puede comenzar el subnivel con sub.

+0

Puntos de originalidad. El alias en sí mismo es probablemente mejor como 'env subshell = true bash' (ya que no se filtrará' $ subshell' a los comandos posteriores): [Usando env] (http://i.imgur.com/XSORn6h.png) vs . [using export] (http://i.imgur.com/SqwdkH8.png). –

+0

Tienes razón. Pero noté que funciona sin 'env' también. Para verificar si está definido o no, utilizo 'echo $ subshell' (en lugar de' env | grep subshell' que usa). – dashohoxha

+0

Creo que también obtiene los puntos por simplicidad. – dashohoxha

Cuestiones relacionadas