Выполнение команд, содержащих пробел в bash - PullRequest
10 голосов
/ 07 мая 2009

У меня есть файл с именем cmd, который содержит список команд Unix следующим образом:

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

У меня есть другой скрипт, который выполняет команды в cmd как:

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

Проблема в том, что команды в cmd без пробелов работают нормально, но те, у которых пробелы, не корректно интерпретируются сценарием. Следующий вывод:

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
****************************

Что мне здесь не хватает?

Ответы [ 6 ]

16 голосов
/ 07 мая 2009

Попробуйте изменить одну строку на eval $cmds, а не просто $cmds

3 голосов
/ 08 мая 2009

Вы можете заменить ваш скрипт командой

sh cmd

Работа оболочки - читать команды и запускать их! Если вам нужны индикаторы вывода / прогресса, запустите оболочку в подробном режиме

sh -v cmd
2 голосов
/ 18 мая 2009

Мне лично этот подход больше нравится - я не хочу вмешиваться в IFS, если мне не нужно этого делать. Вам нужно использовать eval, если вы собираетесь использовать каналы в ваших командах. Канал должен обрабатываться оболочкой, а не командой. Я считаю, что оболочка разбирает трубы перед расширяющимися строками.

Обратите внимание, что, если ваш cmd-файл содержит команды, принимающие ввод, будет проблема. (Но вы всегда можете создать новый fd для чтения команды.)

clear
while read cmds 
do
        if [ -n "$cmds" ] ; then
        eval $cmds
        echo "****************************";
        fi
done < cmd
1 голос
/ 07 мая 2009

Редактировать: Оказывается, это не работает на каналах и перенаправлении. Спасибо, Андомар.

Вам нужно изменить IFS обратно внутри цикла, чтобы bash знал, где разделить аргументы:

IFS=$'\n'
clear
for cmds in `cat cmd`
do
    if [ $cmds ] ; then
        IFS=$' \t\n' # the default
        $cmds;
        echo "****************************";
        IFS=$'\n'
    fi
done
0 голосов
/ 15 апреля 2010
sed 'aecho "-----------"' cmd > cmd.sh; bash cmd.sh

sed 'aXX' добавляет XX к каждой строке. Это не будет работать для многострочных команд, таких как:

for f in * 
do 
    something $f
fi

но для однострочных команд в большинстве случаев так и должно быть.

0 голосов
/ 07 мая 2009

РЕДАКТИРОВАТЬ: комментарий Бена Бланка указал, что мой старый ответ был неправильным, спасибо.

Похоже, вы выполняете команды как одну строку, поэтому bash видит их как имя скрипта / исполняемого файла.

Один из способов избежать этого - вызвать команду bash. Изменения:

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

до

    if [  $cmds ] ; then
    bash -c $cmds
    echo "****************************";
    fi
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...