Почему составная команда с ошибкой не генерирует ошибку?
Есть bash-скрипт со следующей командой:
#!/bin/bash
sudo -u postgres bash -c cd /tmp ; psql -f /tmp/sql.txt
В нем есть ошибка: под пользователем postgres выполняется команда до символов ";", а бинарник psql вызывается уже не под пользователем postgres. И это дает ошибку:
psql: СБОЙ: роль "root" не существует
Так и должно быть.
А теперь есть скрипт, в котором та же самая команда конструируется через переменную:
#!/bin/bash
psqlRun="sudo -u postgres bash -c cd /tmp ; "
$psqlRun psql -f /tmp/sql.txt
Запускаем это дело и... Ошибки нет! Вот только никаких действий, записанных в /tmp/sql.txt в БД PostgreSQL этот скрипт не выполнит. Но и не скажет об этом. Просто молча не сработает и все.
Вопрос: почему так? По-сути, создается команда, всеми символами совпадающая с командой из первого скрипта. Но почему этот скрипт не генерирует ошибку?
Ответы (2 шт):
Потому что ; внутри строки не является разделителем команд.
Простой пример:
a='echo 1 ;'
$a echo 2
выведет 1 ; echo 2, а не 1 и 2.
Можно смотреть что там на самом деле исполняется.
$ cat a.sh
a="echo 1 ;"
$a echo 2
$ bash -x a.sh
+ a='echo 1 ;'
+ echo 1 ';' echo 2
1 ; echo 2
Как видите тут ; заключена в кавычки, т.е. является просто строкой, а не разделителем команд.
В данном случае интерпретатор воспринимает ; как конец команды, а текст после нее следующей командой Что бы передать несколько команд для выполнения от имени пользователя можно установить ограничивающие кавычки:
sudo -u postgres "bash -c cd /tmp ; psql -f /tmp/sql.txt"
Использовать Heredoc:
sudo -u postgres bash << EOF
bash -c cd /tmp
psql -f /tmp/sql.txt
whoami #вывести пользователя под кем запущено выполнение
EOF
Создать скрипт с набором команд:
#script.sh
#Разрешить запуск только под определенным пользователем
[[ `whoami` != postgres ]] && { echo "Доступно для запуска только пользователем postgres"; exit; }
#Набор комманд
bash -c cd /tmp
psql -f /tmp/sql.txt
...
Дать права на запуск скрипту chmod +x ./script.sh и запускать
sudo -u postgres ./script.sh