Почему, 'в то время как IFS = читала' используемый так часто вместо 'IFS =; в то время как считано..'?

Если Вы не хотите звонить sudo some_script можно просто сделать:

  #!/ust/bin/env sh

  sudo /usr/local/scripts/your_script

Программы SETUID должны быть разработаны с большой осторожностью, когда они работают с полномочиями пользователя root, и пользователи имеют большой контроль над ними. Им нужно к проверке работоспособности все. Вы не можете сделать этого со сценариями потому что:

  • Оболочки являются большими частями программного обеспечения, которые взаимодействуют в большой степени с пользователем. Это почти невозможно к проверке работоспособности все — тем более, что большая часть кода не предназначается для выполнения в таком режиме.
  • Сценарии главным образом quick'n'dirty решение и обычно не готовятся с такой осторожностью, чтобы они позволили бы setuid. У них есть много потенциально опасных функций.
  • Они зависят в большой степени от других программ. Не достаточно, что оболочка была проверена. sed, awk, и т.д. должен был бы быть проверен также

Обратите внимание на то, что sudo обеспечивает некоторую проверку исправности, но это не достаточно — проверяют каждую строку в Ваш собственный код.

Как последнее примечание: рассмотрите использование возможностей. Они позволяют Вам давать процесс, работающий как пользователя специальные полномочия, которые обычно требовали бы полномочий пользователя root. Однако, например, в то время как ping потребности управлять сетью, это не должно иметь доступа к файлам. Я не уверен однако, если они наследованы.

82
17.08.2011, 20:48
4 ответа

Прерывание - это

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'.


Вторая часть этого вопроса была объединена здесь, таким образом, я удалил связанный ответ отсюда.

84
27.01.2020, 19:30
  • 1
    Хорошо, кажется, что потенциальное 'прерывание' должно забыть сбрасывать внешнюю IFS... Но я действительно задаюсь вопросом, существует ли также что-то еще в движении... Я имею протестировать вещи здесь, довольно лихорадочно, и у меня есть уведомление, что установка IFS в списке команд while ведет себя qute по-другому, завися, сопровождается ли это двоеточием. Я (еще) не понимаю это поведение, и я теперь задаюсь вопросом, существуют ли некоторые особые условия, включенные на этом уровне..., например. while IFS=X read не разделяет в X, но while IFS=X; read ... –  Peter.O 17.08.2011, 11:44
  • 2
    (Вы имели в виду точку с запятой, правильно?) Второе while не имеет большого смысла - условие для while концы в той точке с запятой, таким образом, нет никакого фактического цикла... read становится просто первой командой в цикле с одним элементом... Или нет? Что относительно do затем..? –  rozcietrzewiacz 17.08.2011, 11:49
  • 3
    Нет, ожидайте - Вы правы, у Вас может быть несколько команд в while условие (прежде чем do). –  rozcietrzewiacz 17.08.2011, 11:55
  • 4
    О.. определенно, у Вас могут быть они..., как Вы поняли..., но им, кажется, не нравится точка с запятой... (и цикл сохранит цикличное выполнение до бесконечности, пока последняя команда не возвратит ненулевой код выхода)... Я теперь задаюсь вопросом, находится ли прерывание в другом секторе полностью; это понимания, как список команд while работает, например, почему делает IFS= работа, но IFS=X не делает... (или возможно у меня есть OD'd на этом некоторое время.. перерыву на кофе был нужен :) –  Peter.O 17.08.2011, 12:21
  • 5
    .. Ой... Я не заметил Ваше обновление, когда я переместил свое обновление (как упомянуто в предыдущем комментарии).. Это выглядит интересным, и это начинает иметь смысл..., но даже для ночной птицы как я, чрезвычайно поздно... (Я просто услышал утренних птиц :)... Тем не менее я сплотился немного и считал Ваши примеры... Я думаю, что у меня есть он, на самом деле я уверен, что у Вас есть он, но я должен спать :)... Это почти Эврика! момент... благодарит –  Peter.O 17.08.2011, 23:40

Давайте посмотрим на пример с некоторым тщательно созданным входным текстом:

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 и зависит от оболочки на практике.

48
27.01.2020, 19:30
  • 1
    Спасибо Gilles.. очень хорошая экскурсия.. (Вы имели в виду 'набор-f'?).... Теперь, для читателя, для повторного заявления, что было уже сказано я хотел бы подчеркнуть проблему, которая имела меня смотрящий на него неправильный путь. Прежде всего то, что конструкция 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"
)
3
27.01.2020, 19:30
  • 1
    +1 превосходная демонстрация, очистка после с 'комнатой *file*with*spaces*' –  amdn 19.01.2017, 21:04

Вдохновленный ответом Yuzem

Если Вы хотите установить IFS к фактическому символу это работало на меня

iconv -f cp1252 zapni.tv.php | while IFS='#' read -d'#' line
do
  echo "$line"
done
0
27.01.2020, 19:30

Теги

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