Установка IFS для одного оператора

Я знаю, что пользовательское значение IFS может быть задано для области одной команды / встроенного. Есть ли способ установить пользовательское значение IFS для одного оператора? По-видимому, нет, поскольку на основании ниже приведена глобальная величина IFS, когда это делается

#check environment IFS value, it is space-tab-newline printf "%s" "$IFS" | od -bc 0000000 040 011 012 \t \n 0000003 #invoke built-in with custom IFS IFS=$'\n' read -r -d '' -a arr <<< "$str" #environment IFS value remains unchanged as seen below printf "%s" "$IFS" | od -bc 0000000 040 011 012 \t \n 0000003 #now attempt to set IFS for a single statement IFS=$'\n' a=($str) #BUT environment IFS value is overwritten as seen below printf "%s" "$IFS" | od -bc 0000000 012 \n 0000001 

  • bash не заканчивается
  • Причина задания SIGTERM в случае закрытия оболочки
  • Как использовать таймер в bash?
  • Может ли bash распознавать объявление переменной как строку, если вы не ставите кавычки?
  • В оболочке bash, как вставить предыдущую строку внутри текущей строки?
  • понять порядок операций для расширения параметра bash
  • Как написать небольшой журнал с bash?
  • Проблема с сценарием UNIX
  • 5 Solutions collect form web for “Установка IFS для одного оператора”

    В некоторых оболочках (включая bash ):

     IFS=: command eval 'p=($PATH)' 

    bash , вы можете опустить command если не в эмуляции sh / POSIX). Но будьте осторожны, что при использовании некотируемых переменных вам также обычно нужно set -f , и в большинстве оболочек нет локальной области.

    С помощью zsh вы можете:

     (){ local IFS=:; p=($=PATH); } 

    $=PATH – это принудительное разбиение слова, которое не выполняется по умолчанию в zsh (globbing при расширении переменной не выполняется ни потому, что вам не нужно set -f если только в эмуляции sh).

    (){...} (или function {...} ) называются анонимными функциями и обычно используются для установки локальной области. с другими оболочками, поддерживающими локальную область функций, вы можете сделать что-то похожее:

     e() { eval "$@"; } e 'local IFS=:; p=($PATH)' 

    Чтобы реализовать локальную область для переменных и параметров в оболочках POSIX, вы также можете использовать функции, предоставляемые по адресу https://github.com/stephane-chazelas/misc-scripts/blob/master/locvar.sh . Затем вы можете использовать его как:

     . /path/to/locvar.sh var=3,2,2 call eval 'locvar IFS; locopt -f; IFS=,; set -- $var; a=$1 b=$2 c=$3' 

    (кстати, недопустимо разбивать $PATH таким образом выше, кроме zsh как и в других оболочках, IFS – это полевой разделитель, а не разделитель полей).

     IFS=$'\n' a=($str) 

    Это всего лишь два назначения, одно за другим, точно так же, как a=1 b=2 .

    Замечание о var=value cmd :

    В:

     var=value cmd arg 

    Оболочка выполняет /path/to/cmd в новом процессе и передает cmd и arg в argv[] и var=value в envp[] . Это не просто назначение переменной, но более передаваемые переменные среды для выполняемой команды. В оболочке Bourne или Korn с set -k вы можете даже написать cmd var=value arg .

    Теперь это не относится к встроенным функциям или функциям, которые не выполняются . В оболочке Bourne, в var=value some-builtin , var заканчивается после этого, как и с var=value . Это означает, например, что поведение var=value echo foo (что не полезно) изменяется в зависимости от того, встроено ли echo или нет.

    POSIX и / или ksh изменили то, что поведение Bourne происходит только для категории встроенных функций, называемых специальными встроенными . eval – это специальная встроенная функция, которую read нет. Для нестандартных встроенных, var=value builtin наборов var только для исполнения встроенного, что заставляет его вести себя аналогично тому, как выполняется внешняя команда.

    command команда может использоваться для удаления специального атрибута этих специальных встроенных функций. То, что POSIX упускает из виду, это то, что для eval и . builtins, это означало бы, что оболочкам придется реализовывать переменный стек (даже если он не указывает local или лимитирующие команды ограничения области), поскольку вы могли бы сделать:

     a=0; a=1 command eval 'a=2 command eval echo \$a; echo $a'; echo $a 

    Или даже:

     a=1 command eval myfunction 

    с myfunction является функция, использующая или устанавливающая $a и потенциально вызывающую command eval .

    Это было действительно упущено, потому что ksh (в котором спецификация в основном основана) не реализовал его (а AT & T ksh и zsh все еще не работает), но в наши дни, кроме тех двух, большинство оболочек реализуют его. Поведение варьируется между раковинами, хотя в таких вещах, как:

     a=0; a=1 command eval a=2; echo "$a" 

    хоть. Использование local оболочек, которые поддерживают его, является более надежным способом реализации локальной области.

    Стандартное сохранение и восстановление, взятое из «Программной среды Unix» Кернигана и Пайка:

     #!/bin/sh old_IFS=$IFS IFS="something_new" some_program_or_builtin IFS=${old_IFS} 

    Поместите скрипт в функцию и вызовите эту функцию, передав ей аргументы командной строки. Поскольку IFS определяется локально, изменения в нем не влияют на глобальную IFS.

     main() { local IFS='/' # the rest goes here } main "$@" 

    Для этой команды:

     IFS=$'\n' a=($str) 

    Существует альтернативное решение: дать первое задание ( IFS=$'\n' ) команду для выполнения (функция):

     $ split(){ a=( $str ); } $ IFS=$'\n' split 

    Это заставит IFS в среде вызвать split, но не сохранится в текущей среде.

    Это также позволяет избежать рискованного использования eval.

    Предлагаемый ответ от @helpermethod – безусловно интересный подход. Но это также немного ловушка, потому что в области локальной переменной BASH распространяется от вызывающего на вызываемую функцию. Поэтому установка IFS в main () приведет к тому, что значение сохраняется для функций, вызываемых из main (). Вот пример:

     #!/usr/bin/env bash # func() { # local IFS='\' local args=${@} echo -n "$FUNCNAME A" for ((i=0; i<${#args[@]}; i++)); do printf "[%s]: %s" "${i}" "${args[$i]}" done echo local f_args=( $(echo "${args[0]}") ) echo -n "$FUNCNAME B" for ((i=0; i<${#f_args[@]}; i++)); do printf "[%s]: %s" "${i}" "${f_args[$i]} " done echo } main() { local IFS='/' # the rest goes here local args=${@} echo -n "$FUNCNAME A" for ((i=0; i<${#args[@]}; i++)); do printf "[%s]: %s" "${i}" "${args[$i]}" done echo local m_args=( $(echo "${args[0]}") ) echo -n "$FUNCNAME B" for ((i=0; i<${#m_args[@]}; i++)); do printf "[%s]: %s" "${i}" "${m_args[$i]} " done echo func "${m_args[*]}" } main "$@" 

    И выход …

     main A[0]: ick/blick/flick main B[0]: ick [1]: blick [2]: flick func A[0]: ick/blick/flick func B[0]: ick [1]: blick [2]: flick 

    Если IFS, объявленный в main (), еще не был включен в func (), тогда массив не был бы правильно разобран в func () B. Раскомментируйте первую строку в func (), и вы получите этот вывод:

     main A[0]: ick/blick/flick main B[0]: ick [1]: blick [2]: flick func A[0]: ick/blick/flick func B[0]: ick/blick/flick 

    Это то, что вы должны получить, если IFS вышел из сферы действия.

    Намного лучшее решение IMHO – это отказаться от изменения или использования IFS на глобальном / местном уровне. Вместо этого создайте новую оболочку и скрипте с IFS. Например, если вы вызывали func () в main () следующим образом, передавая массив как строку с разделителем полей обратной косой черты:

     func $(IFS='\'; echo "${m_args[*]}") 

    … что изменение IFS не будет отражено в функции func (). Массив будет передан как строка:

     ick\blick\flick 

    … но внутри функции func () IFS все равно будет «/» (как указано в main ()), если только локально не изменить в функции func ().

    Более подробную информацию об изоляции изменений в IFS можно посмотреть по следующим ссылкам:

    Как преобразовать переменную массива bash в строку с разделителями строк?

    Строка Bash для массива с IFS

    Советы и рекомендации для общего программирования сценариев оболочки – см. «ПРИМЕЧАНИЕ использования подклассов …»

    Interesting Posts

    Не удается экспортировать пользователя samba с помощью pdbedit. Как я могу сделать резервную копию своих пользователей самбы?

    mv filename .. (Куда будет идти файл?)

    Получить rsync, чтобы сообщить, были ли обновлены локальные файлы

    Время ожидания SSH. это не клиент или сервер … что теперь?

    Какое время, когда linux страдает от дрейфа?

    Сенсорная панель Acer Aspire не обнаружена

    Слияние файлов PDF и автоматическое создание оглавления с каждым файлом в виде записи

    Можно ли позволить фоновому процессу непрерывно выводить на терминал?

    rsync как другой пользователь

    Доступ к серверу через два разных маршрутизатора Wi-Fi

    Asus G752VS, GTX 1070 – аудиоустройство PCI-e (вторая функция) отсутствует

    cp и mv, если уже названный файл

    FreeBSD не перезагружается

    Нет свободного места в буфере – ICMP

    Как перенаправить журналы в syslog для приложения, которое еще не поддерживает syslog?

    Linux и Unix - лучшая ОС в мире.