Почему составная команда с ошибкой не генерирует ошибку?

Есть 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 шт):

Автор решения: Alexey Ten

Потому что ; внутри строки не является разделителем команд.

Простой пример:

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

Как видите тут ; заключена в кавычки, т.е. является просто строкой, а не разделителем команд.

→ Ссылка
Автор решения: ipatev_nn

В данном случае интерпретатор воспринимает ; как конец команды, а текст после нее следующей командой Что бы передать несколько команд для выполнения от имени пользователя можно установить ограничивающие кавычки:

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
→ Ссылка