У меня есть файл, названный 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
****************************
Что я пропускаю здесь?
Попробуйте изменить одну строку на eval $ cmds
, а не просто на $ cmds
Вы можете заменить свой скрипт командой
sh cmd
. Работа оболочки заключается в том, чтобы читать команды и запускать их! Если вам нужны индикаторы вывода / прогресса, запустите оболочку в подробном режиме
sh -v cmd
Изменить: Оказывается, это не работает на каналах и перенаправлении. Спасибо, Андомар.
Вам нужно снова изменить 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
РЕДАКТИРОВАТЬ: В комментарии Бена Бланка указано, что мой старый ответ был неправильным, спасибо.
Похоже, вы выполняете команды как одну строку, поэтому bash видит их как скрипт / имя исполняемого файла.
Один из способов избежать этого - вызвать команду bash. Изменение: с
if [ $cmds ] ; then
$cmds;
echo "****************************";
fi
на
if [ $cmds ] ; then
bash -c $cmds
echo "****************************";
fi
Мне лично этот подход больше нравится - я не хочу изменять IFS , если мне это не нужно. Вам действительно нужно использовать eval, если вы собираетесь использовать каналы в своих командах. Канал должен обрабатываться оболочкой, а не командой. Я считаю, что оболочка разбирает каналы до раскрывающихся строк.
Обратите внимание, что если ваш файл cmd содержит команды, которые принимают ввод, возникнет проблема. (Но вы всегда можете создать новый fd для команды чтения, из которой будет выполняться чтение.)
clear
while read cmds
do
if [ -n "$cmds" ] ; then
eval $cmds
echo "****************************";
fi
done < cmd