Если Вы не хотите звонить sudo some_script
можно просто сделать:
#!/ust/bin/env sh
sudo /usr/local/scripts/your_script
Программы SETUID должны быть разработаны с большой осторожностью, когда они работают с полномочиями пользователя root, и пользователи имеют большой контроль над ними. Им нужно к проверке работоспособности все. Вы не можете сделать этого со сценариями потому что:
sed
, awk
, и т.д. должен был бы быть проверен такжеОбратите внимание на то, что sudo
обеспечивает некоторую проверку исправности, но это не достаточно — проверяют каждую строку в Ваш собственный код.
Как последнее примечание: рассмотрите использование возможностей. Они позволяют Вам давать процесс, работающий как пользователя специальные полномочия, которые обычно требовали бы полномочий пользователя root. Однако, например, в то время как ping
потребности управлять сетью, это не должно иметь доступа к файлам. Я не уверен однако, если они наследованы.
Прерывание - это
IFS=; while read..
наборы IFS
для целой среды оболочки вне цикла, тогда как
while IFS= read
переопределяет его только для read
вызов (кроме Оболочки Bourne). Можно проверить что, делая цикл как
while IFS= read xxx; ... done
затем после такого цикла, echo "blabalbla $IFS ooooooo"
печать
blabalbla
ooooooo
тогда как после
IFS=; read xxx; ... done
IFS
остается переопределенным: теперь echo "blabalbla $IFS ooooooo"
печать
blabalbla ooooooo
Таким образом, при использовании второй формы необходимо не забыть сбрасывать: IFS=$' \t\n'
.
Вторая часть этого вопроса была объединена здесь, таким образом, я удалил связанный ответ отсюда.
Давайте посмотрим на пример с некоторым тщательно созданным входным текстом:
text=' hello world\
foo\bar'
Это - две строки, первое начало с пространства и окончание обратной косой чертой. Во-первых, давайте посмотрим на то, что происходит без любых мер предосторожности вокруг read
(но использование printf '%s\n' "$text"
тщательно распечатать $text
без любого риска расширения). (Ниже, $
приглашение оболочки.)
$ printf '%s\n' "$text" |
while read line; do printf '%s\n' "[$line]"; done
[hello worldfoobar]
read
съел обратные косые черты: новая строка обратной косой черты заставляет новую строку быть проигнорированной, и обратная косая черта - что-либо игнорирует ту первую обратную косую черту. Для предотвращения обратных косых черт, которые рассматривают особенно, мы используем read -r
.
$ printf '%s\n' "$text" |
while read -r line; do printf '%s\n' "[$line]"; done
[hello world\]
[foo\bar]
Это лучше, у нас есть две строки как ожидалось. Эти две строки почти содержат желаемое содержание: двойной интервал между hello
и world
был сохранен, потому что это в line
переменная. С другой стороны, начальное пространство было съедено. Поэтому read
отбрасываются чтения столько слов, сколько Вы передаете его переменные, за исключением того, что последняя переменная содержит остальную часть строки — но это все еще запускается с первого слова, т.е. начальных пробелов.
Так, для чтения каждой строки буквально, мы должны удостовериться, что никакое разделение слова не продолжается. Мы делаем это путем установки IFS
переменная к пустому значению.
$ printf '%s\n' "$text" |
while IFS= read -r line; do printf '%s\n' "[$line]"; done
[ hello world\]
[foo\bar]
Отметьте, как мы устанавливаем IFS
специально для продолжительности read
встроенный. IFS= read -r line
устанавливает переменную среды IFS
(к пустому значению) специально для выполнения read
. Это - экземпляр общего простого синтаксиса команды: (возможно пустой) последовательность переменных присвоений, сопровождаемых названием команды и его аргументами (также, можно добавить перенаправления в любой точке). С тех пор read
встроенное, переменная никогда на самом деле заканчивается в среде внешнего процесса; тем не менее, значение $IFS
то, что мы присваиваем там пока read
выполняет ¹. Отметьте это read
не встроенное специальное предложение, таким образом, присвоение действительно только продолжается в свой период.
Таким образом мы заботимся для не изменения значения IFS
для других инструкций, которые могут полагаться на него. Этот код будет работать независимо от того, что установил окружающий код IFS
к первоначально, и это не доставит неприятностей, если код в цикле будет полагаться IFS
.
Контраст с этим фрагментом кода, который ищет файлы в разделенном от двоеточия пути. Список имен файлов прочитан из файла, одно имя файла на строку.
IFS=":"; set -f
while IFS= read -r name; do
for dir in $PATH; do
## At this point, "$IFS" is still ":"
if [ -e "$dir/$name" ]; then echo "$dir/$name"; fi
done
done <filenames.txt
Если цикл был while IFS=; read -r name; do …
, затем for dir in $PATH
не разделил бы $PATH
в разделенные от двоеточия компоненты. Если код был IFS=; while read …
, это было бы еще более очевидно это IFS
не установлен на :
в теле цикла.
Конечно, было бы возможно восстановить значение IFS
после выполнения read
. Но это потребовало бы знания предыдущего значения, которое является дополнительным усилием. IFS= read
простой путь (и, удобно, также самый короткий путь).
¹ И, если read
прерван захваченным сигналом, возможно в то время как прерывание выполняется — это не указано POSIX и зависит от оболочки на практике.
while IFS= read
(без точки с запятой после =
) не специальная форма while
или IFS
или read
.. Конструкция универсальна: т.е. anyvar=anyvalue anycommand
. Отсутствие ;
после установки anyvar
делает объем anyvar
локальный для anycommand
.. В то время как-/делают, цикл на 100% не связан с локальным объемом any_var
.
– Peter.O
18.08.2011, 08:00
Кроме (уже разъясненный) IFS
обзор различий между while IFS='' read
, IFS=''; while read
и while IFS=''; read
идиомы (на команду по сравнению с script/shell-wide IFS
обзор переменной), урок взятия домой - то, что Вы теряете продвижение и конечные пробелы входной строки, если переменная IFS установлена на (содержите a), пространство.
Это может иметь довольно серьезные последствия, если пути к файлам обрабатываются.
Поэтому установка переменной IFS к пустой строке является совсем не плохой идеей, так как она гарантирует, что ведущий и запаздывающий пробел строки не становится разделенным.
См. также: Bash, читайте линию за линией из файла с IFS
(
shopt -s nullglob
touch ' file with spaces '
IFS=$' \t\n' read -r file <<<"$(printf '%s' *file*with*spaces*)"
ls -l "$file"
IFS='' read -r file <<<"$(printf '%s' *file*with*spaces*)"
ls -l "$file"
)
Вдохновленный ответом Yuzem
Если Вы хотите установить IFS
к фактическому символу это работало на меня
iconv -f cp1252 zapni.tv.php | while IFS='#' read -d'#' line
do
echo "$line"
done
while IFS=X read
не разделяет вX
, ноwhile IFS=X; read
... – Peter.O 17.08.2011, 11:44while
не имеет большого смысла - условие дляwhile
концы в той точке с запятой, таким образом, нет никакого фактического цикла...read
становится просто первой командой в цикле с одним элементом... Или нет? Что относительноdo
затем..? – rozcietrzewiacz 17.08.2011, 11:49while
условие (прежде чемdo
). – rozcietrzewiacz 17.08.2011, 11:55IFS=
работа, ноIFS=X
не делает... (или возможно у меня есть OD'd на этом некоторое время.. перерыву на кофе был нужен :) – Peter.O 17.08.2011, 12:21