Меня смущает сфера применения IFS, разные люди, кажется, думают, что он основан на сеансах, а не только в скрипте, после того как он был установлен / изменен.

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

Если я сделаю что-то вроде:

while IFS='|' read var1 var2 var3

Изменит ли это только значение IFS для этого конкретного цикла while?

3 ответа3

2

Изменит ли это только значение IFS для этого конкретного цикла while?

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

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

#!/bin/bash
while IFS="," read a b; do
  echo $a $b
done < "input.csv"
echo $IFS

Последняя строка вывода будет выглядеть пустой, так как по умолчанию IFS - это <space> , <tab> и <newline> , то есть $' \t\n' . Смотрите спецификации POSIX для деталей .

Если у вас есть (случайно?) установите IFS на какое-то другое значение для всего вашего скрипта, если не unset IFS сбрасывает его на значение по умолчанию.

Кроме того, если под «сессией» вы подразумеваете один сценарий (или оболочку, которая выполняет сценарий), то при выходе из этого сценария значение не будет сохранено. Разумеется, ваш терминал не сохраняет его в течение нескольких сеансов.

1
while IFS='|' read var1 var2 var3

Изменит ли это только значение IFS для этого конкретного цикла while?

Нет. Это только изменит значение IFS для этого конкретного read . В общем, цикл от while до done , он может включать в себя много команд.

Ни IFS ни read здесь не являются особенными. Возьми этот общий код:

( export a=0
printenv a
while a=1 printenv a && printenv a; printenv a; true; do
   printenv a
   break
done; printenv a )

Результат:

0
1
0
0
0
0

Только второй printenv получает измененное значение!

Заметки:

  • Я использовал подоболочку по двум причинам:
    1. вы можете вставить весь код до того, как ваша оболочка выполнит что-либо;
    2. код не будет влиять на переменный в вашей текущей оболочке.
  • Я использовал a , а не printenv a потому что в последнем случае оболочка расширила бы echo $a до значения, видимого самой оболочкой, даже до запуска $a (независимо от того, является ли echo встроенной оболочкой или отдельным исполняемым файлом). Синтаксическая echo почти никогда не изменяет переменную для самой оболочки (исключение составляет variable=foo some_command). Если бы вы изменили каждый параметр variable=foo export variable чтобы он printenv a в моем коде, вы получите все echo $a s.
-1

Да, согласно вашему кодовому блоку, значение IFS устанавливается только для цикла. Как только элемент управления выходит из цикла, IFS получает свое значение до входа в цикл. Это не повлияет на другие операции чтения в том же сценарии оболочки. Я попробовал что-то вроде этого:

echo "Changing IFS value to ','."
OLD_IFS_VALUE=$IFS
IFS='|'
CURRENT_IFS_VALUE=$IFS
echo "IFS value before entering the loop : $CURRENT_IFS_VALUE"
while IFS=',' read name age city gender
do
    echo $name $age $city $gender
done < "testdata1.csv"
echo "After loop value of IFS : $IFS"

Таким образом, я установил IFS на '|' перед петлей. Внутри цикла я использовал значение IFS как ','. После того, как элемент управления вышел из цикла, значение IFS стало '|'.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .