Как правильно временно сохранить и восстановить переменную IFS?

В данном случае «совместимость с sendmail» означает не только совместимость с RFC, но и тот факт, что после установки postfix вы можете запускать большинство основных «знакомых sendmail -» команд, и postfix будет возвращать аналогичные результаты (например, "sendmail -bt" или "mailq" и т. д. ). Преимущество в том, что вы можете запускать postfix, и любое программное обеспечение, которое предполагает использовать sendmail, будет продолжать работать, не зная, что оно использует postfix.

Я бы настоятельно предостерег вас от написания вашего MTA на SMTP. RFC длинные, много раз пересматривались и несколько сложны. Я знаю, потому что я написал MTA для отправки больших объемов -на «C» и ассемблере, а сложности и развитие RFC временами были проблемой. Добавление шифрования, доменных ключей и DKIM, а также SPF и DMARC усложняет процесс. Кроме того, многие другие не -sendmail -MTA нарушают RFC в тот или иной момент. Все должно быть совместимо с sendmail, это стандарт "де-факто".

Я работаю с системами, которые отправляют МИЛЛИАРДЫ зашифрованных сообщений в месяц, и ничто не справляется с объемом почты быстрее или лучше или проще в управлении, чем sendmail. Sendmail немного загадочен, но как только вы поймете некоторые основы, им будет легко управлять и его легко поддерживать.

26
21.03.2021, 11:18
4 ответа

Да, в случае, когда IFSне установлено, восстановление значения из $saved_IFSфактически установит значениеIFS(в пустое значение ).

Это повлияет на способ разделения полей расширений без кавычек, повлияет на разделение полей для readвстроенной утилиты -и повлияет на способ объединения позиционных параметров в строку при использовании "$*".

При неустановленномIFSэти вещи происходили бы так, как если быIFSимело значение пробела, символа табуляции и символа новой строки, но с пустым значение, не будет разделения полей, а позиционные параметры будут объединены в строку без разделителя при использовании "$*". Итак, есть разница.

Чтобы правильно восстановить IFS, рассмотрите установку saved_IFSтолько в том случае, если IFSдействительно имеет какое-либо значение.

unset saved_IFS
[ -n "${IFS+set}" ] && saved_IFS=$IFS

Подстановка параметра ${IFS+set}заменяется на строку set, только если установлено значение IFS, даже если оно установлено на пустую строку. Если IFSне установлено, оно заменяется пустой строкой, что означает, что проверка -nбудет ложной и saved_IFSостанется неустановленной.

Теперь saved_IFSне установлено, если IFSизначально не установлено, или имеет значение, которое было у IFS, и вы можете установить любое значение для IFSи запустить свой код.

При восстановлении IFSвы делаете то же самое:

unset IFS
[ -n "${saved_IFS+set}" ] && { IFS=$saved_IFS; unset saved_IFS; }

Финал unset saved_IFSна самом деле не нужен,но может быть полезно удалить старые переменные из среды.


Альтернативный способ сделать это, предложенный LL3 в комментариях (, теперь удаленный ), основан на префиксе команды unsetпрефиксом :, встроенной -утилитой, которая ничего не делает, эффективно комментируя из unset, когда это не нужно:

saved_IFS=$IFS
${IFS+':'} unset saved_IFS

Это устанавливает saved_IFSв значение $IFS, но затем сбрасывает его, если IFSне было установлено.

Затем установите IFSна свое значение и выполните команды. Затем восстановите с помощью

IFS=$saved_IFS
${saved_IFS+':'} unset IFS

(возможно, за которым следует unset saved_IFS, если вы хотите очистить и эту переменную ).

Обратите внимание, что :должен быть заключен в кавычки, как указано выше, или экранирован как \:, чтобы он не был изменен $IFS, содержащим:(подстановка параметра без кавычек вызывает разделение поля, в конце концов ).

28
28.04.2021, 22:58

В достаточно старых оболочках unsetлибо вообще не существует, либо содержит непригодные для использования ошибки (комментарии в исходном коде Autoconf говорят, что unset IFSможет привести к сбою процесса). Ответ Кусалананды нельзя использовать с такими оболочками.

Если вам нужно беспокоиться об этих старых оболочках, лучше всего установить IFS на пробел, табуляцию и новую строку, именно в таком порядке, как можно раньше:

# There is a hard tab between the second pair of single quotes.
IFS=' ''    ''
'

Этот параметр имеет тот же эффект, что и неустановленный IFS, но его можно безопасно сохранить и восстановить с помощью второй конструкции из вопроса:

saved_IFS="$IFS"; IFS='my value here'
my commands here
IFS="$saved_IFS"

(Двойное -цитирование правой части variable=$othervariableтехнически необязательно, но это облегчает жизнь всем, кому, возможно, придется читать ваш скрипт в будущем, если вы не заставите их запомнить это.)

4
28.04.2021, 22:58

В Bash я бы сделал так:

[ -v IFS ] && oldIFS="$IFS" || unset oldIFS

IFS=something
some commands

[ -v oldIFS ] && IFS="$oldIFS" || unset IFS

или сюда:

[ "${IFS+set}" ] && oldIFS="$IFS" || unset oldIFS

IFS=something
some commands

[ "${oldIFS+set}" ] && IFS="$oldIFS" || unset IFS
0
28.04.2021, 22:58

скопировать

Первоначальная цель — скопировать переменную(a)в другую(b).
Выполнение простого b=$aработает, если aустановлено (либо "", либо значение ), но если aне установлено, bтакже необходимо снять. В противном случае для bбудет установлено значение "".

Неустановленная IFS работает иначе, чем нулевая IFS (в bash):

                             $' \t\n'      unset         null("")
Split Expansions             default       default       no splitting
join arguments with "$*"     "$1c$2c..."   "$1 $2..."   "$1$2"

Итак, нам нужно два шага: скопировать значение и отменить скопированную переменную (при необходимости ). Копию переменной из aв bможно выполнить несколькими способами:

if [ -n "${a+set}" ]; then unset b; else b="$a"; fi
[ -n "${a+set}" ] && unset b || b="$a"
[ "${a+set}" ] && unset b || b="$a"

${a+'false'} && b=$a || unset b

Затем для IFS мы можем скопировать его в oldIFS, изменить значение IFS по мере необходимости и восстановить его после использования:

${IFS+'false'} && oldIFS=$IFS || unset oldIFS

IFS='new value'

${oldIFS+'false'} && IFS=$oldIFS || unset IFS

функция (с)

Единственный способ улучшить это — использовать функцию, и да, функция сможет копировать две переменные:

copyIFS    () { ${IFS+'false'} && oldIFS=$IFS || unset oldIFS; }

при условии, что имена изменяемых переменных известны до написания функции, поскольку функция должна обращаться к таким переменным в глобальной области видимости. localневозможно, declare/typesetне используется.

В shневозможно создать функцию дляcopyvars var1 var2(с переменными var1 и var2 ). Это потребует использования именованных переменных.

Функция восстановления (с использованием замененных имен переменных )— это:

restoreIFS () { ${oldIFS+'false'} && IFS=$oldIFS || unset IFS; }

Определив эти две функции, мы можем сделать:

copyIFS
IFS='a new value'
restoreIFS

Наверное, проще, меньше ошибок.

0
28.04.2021, 22:58

Теги

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