Qual é o escopo do IFS

0

Estou confuso com o escopo do IFS, pessoas diferentes parecem pensar que ele é baseado em sessão vs dentro de um script, uma vez que foi definido / alterado.

Meu problema é que tenho um tempo de leitura que tem colunas potencialmente em branco, o que compensa as variáveis nas quais estou configurando. Se eu alterar o delimitador nos dados de uma guia e atualizar o IFS para usar esse novo delimitador, estou preocupado que isso possa afetar outros comandos de leitura em meu fluxo de trabalho.

Se eu fizer algo como:

while IFS='|' read var1 var2 var3

Isso só alterará o valor do IFS para esse loop while específico?

    
por mike ray 02.08.2017 / 18:00

3 respostas

2

Will that only change the value of IFS for that specific while loop?

Não, na verdade, isso só será alterado para a parte read . Dentro do corpo do loop de while , e depois disso, ele retornará ao seu padrão, porque ele só terá sido definido dentro do contexto do comando read .

Você pode escrever um simples loop sobre algum arquivo que comprove isso, por exemplo com um arquivo CSV com duas colunas:

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

A última linha de saída será exibida vazia, pois por padrão, o IFS é <space> , <tab> e <newline> , portanto $' \t\n' . Veja a especificação POSIX para detalhes .

Se você (acidentalmente?) configurou o IFS para algum outro valor para o script inteiro, unset IFS redefine para o padrão.

Além disso, se por "sessão", você quer dizer um único script (ou shell que executa um script), assim que o script sair, o valor não será salvo. Seu terminal não o preserva em várias sessões, é claro.

    
por 02.08.2017 / 19:39
1
while IFS='|' read var1 var2 var3

Will that only change the value of IFS for that specific while loop?

Não. Ele somente alterará o valor do IFS para esse read específico. Em geral, o loop é de while a done , pode incluir muitos comandos.

Nem IFS nem read são especiais aqui. Tome este código geral:

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

O resultado é:

0
1
0
0
0
0

Apenas o segundo printenv obtém o valor modificado!

Notas:

  • Eu usei um subshell por dois motivos:
    1. você pode colar o código inteiro antes que o seu shell execute qualquer coisa;
    2. o código não afetará a variável a no seu shell atual.
  • Eu usei printenv a , não echo $a porque no último caso o shell expandiria $a para o valor visto pelo o próprio shell antes mesmo de echo iniciado (independentemente se echo é um shell embutido ou um executável separado). A sintaxe variable=foo some_command quase nunca altera a variável para o próprio shell (a exceção é variable=foo export variable ). Se você alterasse todos os printenv a para echo $a no meu código, você obteria todos os 0 -s.
por 20.06.2018 / 11:02
-1

Sim, de acordo com o bloco de códigos, o valor do IFS está sendo definido apenas para o loop. Depois que o controle sai do loop, o IFS obtém seu valor antes de inserir o loop. Isso não afetará outras operações de leitura no mesmo script de shell. Eu tentei algo assim:

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"

Então eu defini o IFS para '|' antes do loop. Dentro do loop, usei o valor do IFS como ','. Depois que o controle saiu do loop, o valor do IFS era '|'.

    
por 20.06.2018 / 09:33

Tags