Установка 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 

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

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

  • использовать backquotes в скрипте
  • вызов bash с опцией -t
  • Сколько данных может содержать переменная bash?
  • Сдвиг аргументов bash справа
  • Почему bash думает: 016 + 1 = 15?
  • cd в каталог и выполнить множество команд
  • Что такое? = В bash?
  • bash добавить путь для обработки некоторых файлов
  • Полностью перезапустите Bash
  • Как мне перебирать список из dconf в bash?
  • Найдите файл с определенным словом внутри этого файла.
  • Interesting Posts

    Как я могу найти файлы, а затем использовать xargs для их перемещения?

    Справочный материал по управлению устройствами

    .bash_profile не используется при запуске su

    Как запустить mod_mono в Debian Jessie (пакет libapache2-mod-mono отсутствует)?

    Объединение / объединение 2 текстовых файлов в соответствии с числовым полем

    .bashrc синтаксическая ошибка рядом с неожиданным токеном `('

    создание архива с использованием tar, включая все «dotfiles», но исключая все подкаталоги и структуру каталога wo

    Shell command / script, чтобы узнать, жив ли хост?

    Может ли программа обнаружить, что она работает на отдельном экране?

    Как указать список установленных пакетов с исходным URI, дистрибутивом и разделом в Debian?

    Используйте Lynx для загрузки источника страницы, на которой я сейчас нахожусь.

    Видеофайлы выглядят зелеными, а не розовыми

    Время меняется внезапно, даже если NTP настроен

    Загрузка HP-UX из SAN

    Неожиданное падение запросов Apache

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