LINUX.ORG.RU

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

 , ,


0

1

Есть 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 этот скрипт не выполнит. Но и не скажет об этом. Просто молча не сработает и все.

Вопрос: почему так? По-сути, создается команда, всеми символами совпадающая с командой из первого скрипта. Но почему этот скрипт не генерирует ошибку?

★★★★★

psqlRun="sudo -u postgres bash -c cd /tmp ; "

Скорее всего, здесь ; из разделителя превращается в аргумент sudo, за которым на второй строчке следуют ещё аргументы для sudo, который честно передаёт их bash:

$ sudo strace -f -e execve bash -x -c cd /tmp foo bar baz
execve("/bin/bash", ["bash", "-x", "-c", "cd", "/tmp", "foo", "bar", "baz"], 0x7ffd6147d4e0 /* 15 vars */) = 0

Если вглядеться, bash в этой ситуации (когда команда -c не заключена в кавычки, чтобы передать её одним аргументом) вообще не смотрит ни на что, кроме cd; остальные аргументы достаются команде в -c в качестве $1, $2, …

$ bash -x -c cd /tmp foo bar baz
+ cd
AITap ★★★★★
()

Когда ты уже прочитаешь man bash. В данном случае, в разделе про word splitting. $psqlRun превращается не в sudo -u postgres bash -c cd /tmp ;, а в 'sudo' '-u' 'postgres' 'bash' '-c' 'cd' '/tmp' ';'

gremlin_the_red ★★★★★
()
Ответ на: комментарий от AITap

остальные аргументы достаются команде в -c в качестве $1, $2, …

Ну опция -c в man bash описана первой и там читать всего ничего.

Если конкретно автору хочется переменных, то можно как-то так:

DIR="/tmp"
CMD="psql -f"
Q="/tmp/sql.txt"
USER="postgres"

sudo -u "$USER" bash -c "cd \$1 ; $CMD \$2" script "$DIR" "$Q"

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)