скрипт bash: разные результаты при вызове с или без sudo

Я думаю, вам не нужно добавлять сгенерированные файлы (PDF, dvi или Postscript) в систему управления версиями; однако имеет смысл скопировать их в синхронизированный каталог или на другой сервер. Я обычно делаю такие вещи с помощью команды make.

У меня есть Makefile, как это, в каталоге, где находятся файлы LaTeX (отступы - это вкладки, а не пробелы). См. GNU Make Manual.

%.pdf: %.tex
        pdflatex  $<
        pdflatex  $<

store_pdf:
        cp example*.pdf path/to/synced_directory

upload_pdf:
        scp example*.pdf user@server.name.com:path/to/directory

clean:
        rm *.log *.aux *.nav *.vrb *.out *.snm *.toc

Если вы хотите переместить файлы в синхронизированный каталог или на сервер, на котором у вас есть доступ к ssh, вам нужно ввести:

make store_pdf
make upload_pdf
[d4 ] Если вы хотите сгенерировать example1.pdf из example1.tex, вам нужно ввести:

make example1.pdf

Если вы хотите удалить файлы, которые вам не нужны, вам нужно ввести: [!d5 ]

make clean
10
задан 25 November 2017 в 18:24

6 ответов

Каждый скрипт начинается с Shebang, без него оболочка, запускающая ваш скрипт, не знает, какой интерпретатор должен запускать ваш скрипт1 и может - как в случае с sudo ./script.sh здесь - запустить его с sh, который в Ubuntu 16.04 связан с dash. Условное выражение [[ является составной командой bash, поэтому dash не знает, как его обрабатывать, и выдает ошибку, с которой вы столкнулись.

Решение состоит в том, чтобы добавить

#!/bin/bash

как первая строка вашего скрипта. Вы можете получить тот же результат, когда вы вызываете его явно с помощью sudo bash ./script.sh, но shebang - это путь. Чтобы проверить, какая оболочка запускает ваш скрипт, добавьте к нему echo $0. Это не то же самое, что echo $SHELL, ссылаясь на Shebang :

SHELL содержит путь к предпочтительной оболочке пользователя. Обратите внимание, что это не обязательно работающая оболочка, хотя Bash устанавливает эту переменную при запуске.

1: Когда вы начали ./test.sh с bash, он просто предположил bash, то же самое относится к подоболочке sudo su.

20
ответ дан 22 May 2018 в 15:54
  • 1
    Также обратите внимание, что bash запускает скрипт без shebang, используя bash, а не /bin/sh. – muru 25 November 2017 в 18:00
  • 2
    @dessert Это исправляет это. Благодаря! Как я могу проверить из скрипта , в котором его запускает? (echo $0 дает мне имя скрипта: ./test.sh) – James Newton 25 November 2017 в 18:01
  • 3
    @JamesNewton нет портативного способа, AFAIK, но вы можете проверить, на что указывает /proc/$$/exe. Также вы можете тестировать различные переменные, такие как $BASH_VERSION, $ZSH_VERSION и т. Д. (Но тире не задана такая переменная) – muru 25 November 2017 в 18:05

Каждый скрипт начинается с Shebang, без него оболочка, запускающая ваш скрипт, не знает, какой интерпретатор должен запускать ваш скрипт1 и может - как в случае с sudo ./script.sh здесь - запустить его с sh, который в Ubuntu 16.04 связан с dash. Условное выражение [[ является составной командой bash, поэтому dash не знает, как его обрабатывать, и выдает ошибку, с которой вы столкнулись.

Решение состоит в том, чтобы добавить

#!/bin/bash

как первая строка вашего скрипта. Вы можете получить тот же результат, когда вы вызываете его явно с помощью sudo bash ./script.sh, но shebang - это путь. Чтобы проверить, какая оболочка запускает ваш скрипт, добавьте к нему echo $0. Это не то же самое, что echo $SHELL, ссылаясь на Shebang :

SHELL содержит путь к предпочтительной оболочке пользователя. Обратите внимание, что это не обязательно работающая оболочка, хотя Bash устанавливает эту переменную при запуске.

1: Когда вы начали ./test.sh с bash, он просто предположил bash, то же самое относится к подоболочке sudo su.

20
ответ дан 18 July 2018 в 02:36

Каждый скрипт начинается с Shebang, без него оболочка, запускающая ваш скрипт, не знает, какой интерпретатор должен запускать ваш скрипт1 и может - как в случае с sudo ./script.sh здесь - запустить его с sh, который в Ubuntu 16.04 связан с dash. Условное выражение [[ является составной командой bash, поэтому dash не знает, как его обрабатывать, и выдает ошибку, с которой вы столкнулись.

Решение состоит в том, чтобы добавить

#!/bin/bash

как первая строка вашего скрипта. Вы можете получить тот же результат, когда вы вызываете его явно с помощью sudo bash ./script.sh, но shebang - это путь. Чтобы проверить, какая оболочка запускает ваш скрипт, добавьте к нему echo $0. Это не то же самое, что echo $SHELL, ссылаясь на Shebang :

SHELL содержит путь к предпочтительной оболочке пользователя. Обратите внимание, что это не обязательно работающая оболочка, хотя Bash устанавливает эту переменную при запуске.

1: Когда вы начали ./test.sh с bash, он просто предположил bash, то же самое относится к подоболочке sudo su.

20
ответ дан 24 July 2018 в 17:36

Как объяснил @dessert, проблема здесь в том, что в вашем скрипте нет строки shebang. Без shebang sudo по умолчанию будет пытаться запустить файл с помощью /bin/sh. Я не мог найти его документированным где-либо, но я подтвердил, проверив исходный код sudo, где я нашел следующее в файле pathnames.h:

#ifndef _PATH_BSHELL
#define _PATH_BSHELL "/bin/sh"
#endif /* _PATH_BSHELL */

Это означает «установить, будет ли переменная [ f10] не определен, установите его на /bin/sh ". Затем в скрипте configure, включенном в исходный tarball, мы имеем:

for p in "/bin/bash" "/usr/bin/sh" "/sbin/sh" "/usr/sbin/sh" "/bin/ksh" "/usr/bin/ksh" "/bin/bash" "/usr/bin/bash"; do
    if test -f "$p"; then
    found=yes
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $p" >&5
$as_echo "$p" >&6; }
    cat >>confdefs.h <<EOF
#define _PATH_BSHELL "$p"
EOF

    break
    fi
done

Этот цикл будет искать /bin/bash, /usr/bin/sh, /sbin/sh, /usr/sbin/sh или /bin/ksh, а затем устанавливает _PATH_BSHELL в зависимости от того, что было найдено первым. Поскольку /bin/sh был первым в списке и существует, _PATH_BSHELL установлен в /bin/sh. Результатом всего этого является то, что оболочка по умолчанию sudo, если не указано иное, - /bin/sh.

Итак, sudo по умолчанию будет запускать вещи, используя /bin/sh, а на Ubuntu, символическую ссылку на dash, минимальную оболочку, совместимую с POSIX:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Feb 27  2015 /bin/sh -> dash
[d7 ] Конструкция [[ является функцией bash, она не определена стандартом POSIX и не понята в dash:

$ bash -c '[[ true ]] && echo yes'
yes
$ dash -c '[[ true ]] && echo yes'
dash: 1: [[: not found

. В трех запросах вы пытались:

./test.sh Нет sudo; в отсутствие строки shebang ваша оболочка попытается выполнить сам файл. Поскольку вы запускаете bash, это будет эффективно запускать bash ./test.sh и работать. sudo su, а затем ./test.sh. Здесь вы запускаете новую оболочку для пользователя root. Это будет любая оболочка, определенная в переменной среды $SHELL для этого пользователя, а на Ubuntu оболочка по умолчанию root bash:
$ grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
sudo ./test.sh Здесь вы позволяете sudo выполнять команду напрямую. Поскольку его оболочка по умолчанию /bin/sh, как объяснялось выше, это заставляет запустить сценарий с /bin/sh, который является dash, и он терпит неудачу, поскольку dash не понимает [[.

Примечание: подробности о том, как sudo устанавливает оболочку по умолчанию, кажутся немного более сложными. Я попытался изменить файлы, упомянутые в моем ответе, чтобы указать на /bin/bash, но sudo по-прежнему по умолчанию /bin/sh. Таким образом, в исходном коде должны быть некоторые другие места, где определена оболочка по умолчанию. Тем не менее, основной момент (по умолчанию sudo по умолчанию sh).

5
ответ дан 22 May 2018 в 15:54
  • 1
    Я не мог найти его документированным где-либо - мне тоже, я просто предположил, что он будет использовать /bin/sh из сообщения об ошибке - что еще можно было бы сделать? Ответ на вопрос красиво в . Какая оболочка использует sudo · SO , см. Также man sudo, раздел COMMAND EXECUTION . Выключается sudo не использует промежуточную оболочку ! – dessert 25 November 2017 в 22:04
  • 2
    @dessert yes, он использует собственную реализацию системного вызова execve, который по умолчанию имеет значение sh. И нет, промежуточные оболочки не имеют значения, это не о оболочке, которая запускает команду, а о интерпретаторе оболочки, используемом для чтения данного сценария оболочки. Таким образом, нет, он не запускает промежуточную оболочку, но для интерпретатора оболочки все еще нужен интерпретатор оболочки. – terdon♦ 25 November 2017 в 22:09

Как объяснил @dessert, проблема здесь в том, что в вашем скрипте нет строки shebang. Без shebang sudo по умолчанию будет пытаться запустить файл с помощью /bin/sh. Я не мог найти его документированным где-либо, но я подтвердил, проверив исходный код sudo, где я нашел следующее в файле pathnames.h:

#ifndef _PATH_BSHELL #define _PATH_BSHELL "/bin/sh" #endif /* _PATH_BSHELL */

Это означает «установить, будет ли переменная _PATH_BSHELL не определен, установите его на /bin/sh ". Затем в скрипте configure, включенном в исходный tarball, мы имеем:

for p in "/bin/bash" "/usr/bin/sh" "/sbin/sh" "/usr/sbin/sh" "/bin/ksh" "/usr/bin/ksh" "/bin/bash" "/usr/bin/bash"; do if test -f "$p"; then found=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $p" >&5 $as_echo "$p" >&6; } cat >>confdefs.h <<EOF #define _PATH_BSHELL "$p" EOF break fi done

Этот цикл будет искать /bin/bash, /usr/bin/sh, /sbin/sh, /usr/sbin/sh или /bin/ksh, а затем устанавливает _PATH_BSHELL в зависимости от того, что было найдено первым. Поскольку /bin/sh был первым в списке и существует, _PATH_BSHELL установлен в /bin/sh. Результатом всего этого является то, что оболочка по умолчанию sudo, если не указано иное, - /bin/sh.

Итак, sudo по умолчанию будет запускать вещи, используя /bin/sh, а на Ubuntu, символическую ссылку на dash, минимальную оболочку, совместимую с POSIX:

$ ls -l /bin/sh lrwxrwxrwx 1 root root 4 Feb 27 2015 /bin/sh -> dash

Конструкция [[ является функцией bash, она не определена стандартом POSIX и не понята в dash:

$ bash -c '[[ true ]] && echo yes' yes $ dash -c '[[ true ]] && echo yes' dash: 1: [[: not found

. В трех запросах вы пытались:

./test.sh Нет sudo; в отсутствие строки shebang ваша оболочка попытается выполнить сам файл. Поскольку вы запускаете bash, это будет эффективно запускать bash ./test.sh и работать. sudo su, а затем ./test.sh. Здесь вы запускаете новую оболочку для пользователя root. Это будет любая оболочка, определенная в переменной среды $SHELL для этого пользователя, а на Ubuntu оболочка по умолчанию root bash: $ grep root /etc/passwd root:x:0:0:root:/root:/bin/bash sudo ./test.sh Здесь вы позволяете sudo выполнять команду напрямую. Поскольку его оболочка по умолчанию /bin/sh, как объяснялось выше, это заставляет запустить сценарий с /bin/sh, который является dash, и он терпит неудачу, поскольку dash не понимает [[.

Примечание: подробности о том, как sudo устанавливает оболочку по умолчанию, кажутся немного более сложными. Я попытался изменить файлы, упомянутые в моем ответе, чтобы указать на /bin/bash, но sudo по-прежнему по умолчанию /bin/sh. Таким образом, в исходном коде должны быть некоторые другие места, где определена оболочка по умолчанию. Тем не менее, основной момент (по умолчанию sudo по умолчанию sh).

5
ответ дан 18 July 2018 в 02:36

Как объяснил @dessert, проблема здесь в том, что в вашем скрипте нет строки shebang. Без shebang sudo по умолчанию будет пытаться запустить файл с помощью /bin/sh. Я не мог найти его документированным где-либо, но я подтвердил, проверив исходный код sudo, где я нашел следующее в файле pathnames.h:

#ifndef _PATH_BSHELL #define _PATH_BSHELL "/bin/sh" #endif /* _PATH_BSHELL */

Это означает «установить, будет ли переменная _PATH_BSHELL не определен, установите его на /bin/sh ". Затем в скрипте configure, включенном в исходный tarball, мы имеем:

for p in "/bin/bash" "/usr/bin/sh" "/sbin/sh" "/usr/sbin/sh" "/bin/ksh" "/usr/bin/ksh" "/bin/bash" "/usr/bin/bash"; do if test -f "$p"; then found=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $p" >&5 $as_echo "$p" >&6; } cat >>confdefs.h <<EOF #define _PATH_BSHELL "$p" EOF break fi done

Этот цикл будет искать /bin/bash, /usr/bin/sh, /sbin/sh, /usr/sbin/sh или /bin/ksh, а затем устанавливает _PATH_BSHELL в зависимости от того, что было найдено первым. Поскольку /bin/sh был первым в списке и существует, _PATH_BSHELL установлен в /bin/sh. Результатом всего этого является то, что оболочка по умолчанию sudo, если не указано иное, - /bin/sh.

Итак, sudo по умолчанию будет запускать вещи, используя /bin/sh, а на Ubuntu, символическую ссылку на dash, минимальную оболочку, совместимую с POSIX:

$ ls -l /bin/sh lrwxrwxrwx 1 root root 4 Feb 27 2015 /bin/sh -> dash

Конструкция [[ является функцией bash, она не определена стандартом POSIX и не понята в dash:

$ bash -c '[[ true ]] && echo yes' yes $ dash -c '[[ true ]] && echo yes' dash: 1: [[: not found

. В трех запросах вы пытались:

./test.sh Нет sudo; в отсутствие строки shebang ваша оболочка попытается выполнить сам файл. Поскольку вы запускаете bash, это будет эффективно запускать bash ./test.sh и работать. sudo su, а затем ./test.sh. Здесь вы запускаете новую оболочку для пользователя root. Это будет любая оболочка, определенная в переменной среды $SHELL для этого пользователя, а на Ubuntu оболочка по умолчанию root bash: $ grep root /etc/passwd root:x:0:0:root:/root:/bin/bash sudo ./test.sh Здесь вы позволяете sudo выполнять команду напрямую. Поскольку его оболочка по умолчанию /bin/sh, как объяснялось выше, это заставляет запустить сценарий с /bin/sh, который является dash, и он терпит неудачу, поскольку dash не понимает [[.

Примечание: подробности о том, как sudo устанавливает оболочку по умолчанию, кажутся немного более сложными. Я попытался изменить файлы, упомянутые в моем ответе, чтобы указать на /bin/bash, но sudo по-прежнему по умолчанию /bin/sh. Таким образом, в исходном коде должны быть некоторые другие места, где определена оболочка по умолчанию. Тем не менее, основной момент (по умолчанию sudo по умолчанию sh).

5
ответ дан 24 July 2018 в 17:36
  • 1
    Я не мог найти его документированным где-либо - мне тоже, я просто предположил, что он будет использовать /bin/sh из сообщения об ошибке - что еще можно было бы сделать? Ответ на вопрос красиво в . Какая оболочка использует sudo · SO , см. Также man sudo, раздел COMMAND EXECUTION . Выключается sudo не использует промежуточную оболочку ! – dessert 25 November 2017 в 22:04
  • 2
    @dessert yes, он использует собственную реализацию системного вызова execve, который по умолчанию имеет значение sh. И нет, промежуточные оболочки не имеют значения, это не о оболочке, которая запускает команду, а о интерпретаторе оболочки, используемом для чтения данного сценария оболочки. Таким образом, нет, он не запускает промежуточную оболочку, но для интерпретатора оболочки все еще нужен интерпретатор оболочки. – terdon♦ 25 November 2017 в 22:09

Другие вопросы по тегам:

Похожие вопросы: