Bash Script – Variável de ambiente IFS

Linguagem BASH.

A variável de ambiente IFS é uma variável importante do BASH, é usada para informar o BASH qual separador usar para separar palavras em uma linha de texto por exemplo, ou em argumentos passados para scripts.

Neste artigo pretendo mostrar como podemos usa la e modifica-la a nosso gosto.

Modificar esta variável em determinadas situações tem vantagens, em outras não no entanto temos que perceber como funciona para podermos tomar a decisão, se devemos ou não modifica-la.

Todos os scripts de exemplo, encontram se no final do artigo, podem ser descarregados.

Valor por defeito

O valor por defeito desta variável é <space><tab><newline>.

Isto é o normal, quando lançamos comandos com argumentos separamos os argumentos com espaço. Quando criamos algum texto usamos espaço para separar a palavras e tabs para indentar algum texto e enter(newline) para mudar de linha. Por estas razões e talvez outras foram escolhidos estes separadores por defeito.

Verificar o valor por defeito

Para podermos verificar o valor por defeito, podemos correr o script “IFS_ex_1.sh”:

#!/bin/bash

#IFS_ex_1.sh

# Verificar o valor por defeito da variável IFS
echo "Verificar o valor por defeito da variável IFS"

printf "O valor atual é %q" "$IFS"
echo
miguel@terra:~/bash$ ./IFS_ex_1.sh
Verificar o valor por defeito da variável IFS
O valor atual é $' \t\n'

Visto que os caracteres usados não são visíveis temos de escapa-los para vermos. Isto é feito com o comando printf.

Modificando a variável IFS

Existe em determinadas situações a necessidade de modificar a variável IFS para que os nosso scripts se tornem mais simples. E consigam adaptar se melhor com os dados que estamos a lidar.

Os que tenham interesse, podem ver aqui um caso real onde modifico bastante a variável IFS para se adaptar aos dados.

Imaginemos uma lista com nome e email de pessoas da seguinte forma:

Miguel Caldeira miguel@exemplo.com
Maria Gertrudes mariag@exemplo.com
Rita Maria Gertrudes rmariag@exemplo.com

Claro que poderíamos processar estes dados sem modificar a variável IFS.

Neste caso por exemplo sabemos de certeza que o ultimo argumento é o email da pessoa em questão e que todos os outros são o seu nome. Simples. Apesar de nem todos terem o mesmo numero de nomes. No entanto como só temos o nome e email e sabemos que o email não tem espaços e é sempre escrito em último é fácil processar estes dados.

Podemos processar estes dados com o seguinte script:

#!/bin/bash

#IFS_ex_2.sh

# Esta variável é uma copia dos parâmetros passados por argumento
dados=$@

# Remover o nome
# Apaga tudo a partir do inicio até encontrar o ultimo espaço " "
echo "Email: ${dados##* }"

# Remover o email
# Apaga tudo a partir do fim até encontrar o " "
echo "Nome: ${dados% *}"
miguel@terra:~/bash$ ./IFS_ex_2.sh Miguel Caldeira miguel@exemplo.com
Email: miguel@exemplo.com
Nome: Miguel Caldeira

Apesar de nesta situação ser fácil processar estes dados, tudo ficaria mais complicado caso se tenha mais de que um dado que contenha espaços.

Imaginemos a seguinte lista que contem nome, morada e email:

Miguel Caldeira rua sésamo miguel@exemplo.com
Maria Gertrudes rua sésamo mariag@exemplo.com
Rita Maria Gertrudes rua sésamo rmariag@exemplo.com

Claro que nós humanos se lermos com atenção conseguimos separar o nome a morada e o email. No entanto para o BASH todos os espaços são iguais. Seria bastante difícil separar estes dados usando como separador o espaço ” “.

Nesta situação torna-se muito mais fácil atribuir um separador diferente para separar os dados. No entanto este separador não pode aparecer nos dados.

Desta forma é possível separar os dados de cada pessoa em três partes independentemente do numero de palavras que cada parte tenha. Neste exemplo vou usar o sinal (+) que não faz parte de nomes nem moradas nem emails.

Da seguinte forma:

Miguel Caldeira+Rua Sésamo+miguel@exemplo.com
Maria Gertrudes+Rua Sésamo+mariag@exemplo.com
Rita Maria Gertrudes+Rua Sésamo+rmariag@exemplo.com

Desta forma apesar dos nomes conterem espaços bem como a morada não existe problema pois o que os separa é o sinal “+”.

No seguinte script BASH a variável IFS é configurada para usar o sinal “+” como separador:

#!/bin/bash

#IFS_ex_3.sh

# Configurar o BASH para usar o sinal '+' como separador
IFS='+'

# Criar o array 'pessoadados' com os valores passados por argumento
# para o script separando o valores por '+'
read -a pessoadados <<< "$@"

# Tendo o array com os dados podemos usar a gosto
# no decorrer do script.

# O nome da pessoa passado por argumento
echo "Nome: ${pessoadados[0]}"

# Morada da pessoa passado por argumento
echo "Morada: ${pessoadados[1]}"

# O email da pessoa passado por argumento
echo "Email: ${pessoadados[2]}"

Quando corremos o script anterior com os dados separados com o sinal ‘+’ temos o seguinte output.

miguel@terra:~/bash$ ./IFS_ex_3.sh Rita Maria Gertrudes+Rua Sésamo+rmariag@exemplo.com
Nome: Rita Maria Gertrudes
Morada: Rua Sésamo
Email: rmariag@exemplo.com

Nos exemplos acima os dados de cada pessoa são inseridos como argumento para o script, no entanto os dados podem ser obtidos de ficheiros ou até mesmo através dos dados resultantes de o processamento de um comando.

Os argumentos e a variável IFS

Quando trabalhamos com argumentos, usamos as variáveis especiais “$@”, “$*” bem como “$0”, “$1”, “$n”, para ter acesso aos valores passados por argumento.

No entanto apenas as variáveis “$@” e “$*” são influenciadas pela variável de ambiente “IFS”.

Reset a variável IFS

Normalmente modificamos a variável IFS para obter e organizar os dados em strings ou arrays, depois podemos fazer reset a esta variável. A forma que temos para fazer isto é criando uma copia da variável IFS logo no inicio do script para mais tarde repor o seu valor para usar no resto do script.

O seguinte script exemplifica isto:

#!/bin/bash

#IFS_ex_4.sh

# Guardar o valor por defeito da variável IFS.
OLDIFS=$IFS

# Configurar o BASH para usar o sinal '+' como separador
# desta forma podemos separar os argumentos com o sinal '+'
IFS='+'

# Criar u array 'pessoadados' com os valores passados por argumento para o script
# separando o valores por '+'
read -a pessoadados <<< "$@"

# Tendo o array com os dados podemos usar a gosto no decorrer do script.

# O nome da pessoa passado por argumento
echo "Nome: ${pessoadados[0]}"

# Morada da pessoa passado por argumento
echo "Morada: ${pessoadados[1]}"

# O email da pessoa passado por argumento
echo "Email: ${pessoadados[2]}"

# Como já temos os nossos dados organizados podemos repor o valor da variável IFS
# com o seu valor por defeito para usar no resto do script.
IFS=$OLDIFS

Conclusão

Por vezes é importante usar a variável IFS para ler dados formatados, pois de outra forma complicaria todo o script para fazer algo bem simples.

Temos de ter o cuidado em repor o valor da variável IFS, se pretendermos ler dados separados por espaço no decorrer do script.

Espero que tenha sido claro e que qualquer um possa perceber este artigo e que possa tirar proveito dele.

Qualquer questão comentem ou usem o grupo Bash Script.

Anexos

Artigos Relacionados:

4 comentários sobre “Bash Script – Variável de ambiente IFS

  1. Joaquim Lobo Netosays:

    Olá José Miguel, felizmente um mecanismo de pesquisa trouxe-me até aqui, sorte a minha pois os seus artigos sobre bash scripts são muito bons.
    Comecei aprendendo do zero lendo-os e já aprendi muito, mas tenho uma dúvida; não encontrei nos artigos um comando: read -a pessoadados <<< "$@" que você usou no exemplo #IFS_ex_3.sh.
    Ficarei muito agradecido se você puder comentar sobre o "read -a" e também "<<<".
    Desejo a você muita prosperidade e o meu sincero incentivo na continuação dos artigos de bash script.

      • Joaquim Lobo Netosays:

        José Miguel, muitíssimo obrigado pela atenção e não se sinta culpado pois o seu trabalho é ótimo.
        Vou aproveitar a oportunidade e pedir mais uma orientação!
        No script IFS_ex_3.sh se eu acrescentasse no final dele as seguintes linhas:
        # Número de argumentos
        echo “Foram passados ao script $# argumentos”
        # Argumentos
        echo “O argumento um é : $1”
        echo “O argumento dois é : $2”
        echo “O argumento três é : $3”
        echo “O argumento quatro é : $4”
        que você usou no script var_especiais_ex_1.sh do artigo de variáveis especiais, ao corrermos o script com os dados separados com o sinal ‘+’ temos o seguinte output:
        miguel@terra:~/bash$ ./IFS_ex_3.sh Rita Maria Gertrudes+Rua Sésamo+rmariag@exemplo.com

        Nome: Rita Maria Gertrudes
        Morada: Rua Sésamo
        Email: rmaria@exemplo.com
        Foram passados ao script 4 argumentos
        O argumento um é : Rita
        O argumento dois é : Maria
        O argumento três é : Gertrudes+Rua
        O argumento quatro é : Sésamo+rmaria@exemplo.com

        Percebi que o sinal ‘+’ não afetou as variáveis $1, $2, $3 e $4, então eu pergunto: Há alguma maneira de aplicar a estas variáveis o mesmo comportamento dado a variável $IFS?

        • Olá Joaquim, disponha!

          Se possível gostava que se regista-se no site e usa-se o grupo https://www.ncdc.pt/groups/bash-script/.
          Não é obrigatório, mas seria uma melhor forma de separar assuntos. E permitir que outros tenham acesso de forma mais simples ás mesmas perguntas.

          A variável IFS apenas afeta a variável especial ‘$@’ e ‘$*’.

          Se pretender usar um argumento levando em conta a ação da variável IFS, no script “./IFS_ex_3.sh” utilize o comando “read”.

          Ficaria assim o script:

          #!/bin/bash

          #IFS_ex_3.sh

          # Configurar o BASH para usar o sinal ‘+’ como separador
          IFS=’+’

          # Criar u array ‘pessoadados’ com os valores passados por argumento para o script
          # separando o valores por ‘+’
          read -a pessoadados <<< "$@"

          # Tendo o array com os dados podemos usar a gosto no decorrer do script.

          # O nome da pessoa passado por argumento
          echo "Nome: ${pessoadados[0]}"

          # Morada da pessoa passado por argumento
          echo "Morada: ${pessoadados[1]}"

          # O email da pessoa passado por argumento
          echo "Email: ${pessoadados[2]}"

          # Número de argumentos
          echo "Foram passados ao script ${#pessoadados[@]} argumentos"
          # Argumentos
          echo "O argumento um é : ${pessoadados[0]}"
          echo "O argumento dois é : ${pessoadados[1]}"
          echo "O argumento três é : ${pessoadados[2]}"

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *