В данном случае «совместимость с 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 немного загадочен, но как только вы поймете некоторые основы, им будет легко управлять и его легко поддерживать.
Да, в случае, когда 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
, содержащим:
(подстановка параметра без кавычек вызывает разделение поля, в конце концов ).
В достаточно старых оболочках 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
технически необязательно, но это облегчает жизнь всем, кому, возможно, придется читать ваш скрипт в будущем, если вы не заставите их запомнить это.)
В 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
Первоначальная цель — скопировать переменную(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
Наверное, проще, меньше ошибок.