2009-05-07 14 views
7

tengo un archivo llamado cmd que contiene una lista de comandos unix de la siguiente manera:La ejecución de comandos que contienen espacio en bash

hostname 
pwd 
ls /tmp 
cat /etc/hostname 
ls -la 
ps -ef | grep java 
cat cmd 

tengo otro script que ejecuta los comandos de cmd como:

IFS=$'\n' 
clear 
for cmds in `cat cmd` 
do 
     if [ $cmds ] ; then 
     $cmds; 
     echo "****************************"; 
     fi 
done 

El problema es que los comandos en cmd sin espacios funcionan bien, pero aquellos con espacios no son interpretados correctamente por el script. A continuación se muestra el resultado:

patrick-laptop 
**************************** 
/home/patrick/bashFiles 
**************************** 
./prog.sh: line 6: ls /tmp: No such file or directory 
**************************** 
./prog.sh: line 6: cat /etc/hostname: No such file or directory 
**************************** 
./prog.sh: line 6: ls -la: command not found 
**************************** 
./prog.sh: line 6: ps -ef | grep java: command not found 
**************************** 
./prog.sh: line 6: cat cmd: command not found 
**************************** 

¿Qué me falta aquí?

Respuesta

13

Prueba a cambiar la línea a eval $cmds en lugar de sólo $cmds

0

EDITAR: El comentario de Ben Blank señaló que mi respuesta anterior era incorrecta, gracias.

Parece que está ejecutando comandos como una sola cadena, por lo que bash los ve como el script/nombre ejecutable.

Una forma de evitarlo sería invocar bash al comando. Cambio:

if [ $cmds ] ; then 
    $cmds; 
    echo "****************************"; 
    fi 

a

if [ $cmds ] ; then 
    bash -c $cmds 
    echo "****************************"; 
    fi 
+1

En realidad, tiene el problema opuesto.Establecer $ IFS como lo hizo aquí hace que 'for' se rompa en las líneas nuevas, exactamente como él quiere. Sin embargo, está intentando interpretar la cadena completa como un nombre de comando en lugar de un comando con argumentos. –

+0

+1 para compensar downvote. :-) –

+0

invocando bash -c está comenzando un nuevo proceso para cada comando. Eso parece excesivo y podría tener resultados sorprendentes. Por ejemplo, si uno de los comandos es un comando cd, los comandos posteriores no se ejecutarán en ese otro directorio. –

1

Editar: Resulta que esto no funciona en tuberías y la redirección. Gracias, Andomar.

necesita cambiar IFS vuelta dentro del bucle de manera que Bash sabe dónde dividir los argumentos:

IFS=$'\n' 
clear 
for cmds in `cat cmd` 
do 
    if [ $cmds ] ; then 
     IFS=$' \t\n' # the default 
     $cmds; 
     echo "****************************"; 
     IFS=$'\n' 
    fi 
done 
+0

-1, lo probé, falla en el comando "ps -ef | grep java". – Andomar

3

Puede reemplazar el script con el comando

sh cmd 

¡El trabajo del intérprete de comandos es leer los comandos y ejecutarlos! Si desea que los indicadores de salida/de progreso, ejecutar el shell en modo detallado

sh -v cmd 
2

personalmente me gusta este enfoque mejor - no quiero a los munge IFS si no tengo que hacerlo. Necesitas usar un eval si vas a usar pipes en tus comandos. La tubería necesita ser procesada por el shell y no por el comando. Creo que el shell analiza las tuberías antes de las cadenas en expansión.

Tenga en cuenta que si su archivo cmd contiene comandos que reciben información, habrá un problema. (Pero siempre se puede crear un nuevo fd para el comando de lectura para leer.)

clear 
while read cmds 
do 
     if [ -n "$cmds" ] ; then 
     eval $cmds 
     echo "****************************"; 
     fi 
done < cmd 
+0

proDir = $ {PROJECT_DIR}, donde PROJECT_DIR contiene espacio en el directorio. Probado con eval $ {PROJECT_DIR} no funciona, ¿alguien dará sugerencias? – arunit21

0
sed 'aecho "-----------"' cmd > cmd.sh; bash cmd.sh 

sed 'AXX' anexa a cada línea XX. Esto no funcionará para varias líneas comandos como:

for f in * 
do 
    something $f 
fi 

pero para los comandos de una sola línea en la mayoría de los casos, se debe hacer.

Cuestiones relacionadas