Eu tenho o seguinte arquivo .txt:
Marco
Paolo
Antonio
Eu quero lê-lo linha por linha, e para cada linha eu quero atribuir um valor de linha .txt a uma variável. Supondo que minha variável seja $name
, o fluxo é:
- Ler a primeira linha do arquivo
- Atribuir
$name
= "Marco" - Faça algumas tarefas com
$name
- Ler a segunda linha do arquivo
- Atribuir
$name
= "Paolo"
Respostas:
A seguir, um arquivo passado como um argumento linha por linha:
Este é o formulário padrão para ler linhas de um arquivo em um loop. Explicação:
IFS=
(ouIFS=''
) impede que os espaços em branco à esquerda / à direita sejam cortados.-r
impede que as fugas de barra invertida sejam interpretadas.Ou você pode colocá-lo em um script auxiliar de arquivo bash, como exemplo de conteúdo:
Se o acima foi salvo em um script com nome de arquivo
readfile
, ele poderá ser executado da seguinte maneira:Se o arquivo não for um arquivo de texto POSIX padrão (= não finalizado por um caractere de nova linha), o loop poderá ser modificado para manipular linhas parciais finais:
Aqui,
|| [[ -n $line ]]
impede que a última linha seja ignorada se não terminar com a\n
(desde queread
retorna um código de saída diferente de zero quando encontrar EOF).Se os comandos dentro do loop também lerem da entrada padrão, o descritor de arquivo usado
read
pode ser alterado para outra coisa (evite os descritores de arquivo padrão ), por exemplo:(Os shells não Bash podem não saber
read -u3
; use emread <&3
vez disso.)fonte
ssh
sem o-n
sinalizador efetivamente fará com que você escape do loop. Provavelmente, há uma boa razão para isso, mas demorei um pouco para identificar o que estava causando a falha do meu código antes que eu descobrisse isso.ffmpeg
consumo de stdin. Adicione</dev/null
à suaffmpeg
linha e ela não poderá, ou usar um FD alternativo para o loop. Essa abordagem de "FD alternativo" parecewhile IFS='' read -r line <&3 || [[ -n "$line" ]]; do ...; done 3<"$1"
..sh
extensão. Os executáveis no UNIX normalmente não têm extensões (você não executals.elf
), e ter um shebang do bash (e ferramentas somente do bash, como[[ ]]
) e uma extensão que implique compatibilidade com POSIX sh é internamente contraditório.Convido você a usar a
-r
bandeiraread
que significa:Eu estou citando
man 1 read
.Outra coisa é usar um nome de arquivo como argumento.
Aqui está o código atualizado:
fonte
sh
não estavabash
; o comando de teste estendido usado na|| [[ -n "$line" ]]
sintaxe na resposta aceita é um basismo. Dito isso, a sintaxe realmente tem um significado pertinente: faz com que o loop continue na última linha do arquivo de entrada, mesmo que não tenha uma nova linha. Se você quiser fazer isso de uma maneira compatível com POSIX|| [ -n "$line" ]
, use, em[
vez de[[
.IFS=
para oread
para evitar aparar espaço em branco.O uso do modelo Bash a seguir deve permitir que você leia um valor de cada vez de um arquivo e processe-o.
fonte
*
.fonte
Enter
após a última linha), caso contrário, a última linha será ignorada. Pelo menos foi o que aconteceu comigo.Muitas pessoas postaram uma solução super otimizada. Não acho que esteja incorreto, mas acho humildemente que uma solução menos otimizada será desejável para permitir que todos compreendam facilmente como isso está funcionando. Aqui está a minha proposta:
fonte
Usar:
Se você definir de forma
IFS
diferente, obterá resultados ímpares.fonte
*
em uma linha? Enfim, este é um antipadrão . Não leia linhas com para .read
abordagem é a melhor prática por consenso da comunidade . A ressalva que você menciona no seu comentário é aquela que se aplica quando o loop executa comandos (comoffmpeg
) que são lidos no stdin, resolvidos trivialmente usando um FD não stdin para o loop ou redirecionando a entrada desses comandos. Por outro lado, contornar o bug globbing na suafor
abordagem -loop significa fazer (e depois precisar reverter) as mudanças nas configurações globais do shell.for
abordagem de loop usada aqui significa que todo o conteúdo deve ser lido antes que o loop possa começar a ser executado, tornando-o totalmente inutilizável se você estiver repetindo gigabytes de dados, mesmo que tenha desativado globbing; owhile read
loop precisa armazenar não mais do que os dados de uma única linha de cada vez, o que significa que ele pode começar a executar enquanto o subprocesso que gera conteúdo ainda estiver em execução (sendo assim utilizável para fins de streaming) e também limitar o consumo de memória.while
abordagens uniformes parecem ter problemas com * caracteres. Veja os comentários da resposta aceita acima. Porém, não argumentando contra a iteração de arquivos ser um antipadrão.Se você precisar processar o arquivo de entrada e a entrada do usuário (ou qualquer outra coisa do stdin), use a seguinte solução:
Com base na resposta aceita e no tutorial de redirecionamento bash-hackers .
Aqui, abrimos o descritor de arquivo 3 para o arquivo passado como argumento do script e pedimos
read
para usar esse descritor como input (-u 3
). Assim, deixamos o descritor de entrada padrão (0) conectado a um terminal ou outra fonte de entrada, capaz de ler a entrada do usuário.fonte
Para manipulação adequada de erros:
fonte
A seguir, apenas será impresso o conteúdo do arquivo:
fonte
Use a ferramenta IFS (separador de campo interno) no bash, define o caractere usado para separar linhas em tokens; por padrão, inclui < tab > / < space > / < newLine >
Etapa 1 : Carregue os dados do arquivo e insira na lista:
etapa 2 : agora itere e imprima a saída:
eco índice específico na matriz : Acessando uma variável na matriz:
fonte