É bem fácil ler o conteúdo de uma linha de arquivo de texto Linux por linha em um script de shell - contanto que você lide com algumas Gotchas sutis. Veja como fazer isso de maneira segura.
Arquivos, texto e idiomas
Cada linguagem de programação tem um conjunto de idiomas. Estas são as formas padrão, sem frescuras de realizar um conjunto de tarefas comuns. Eles são a maneira elementar ou padrão de usar um dos recursos da linguagem que o programador está funcionando. Eles se tornam parte do kit de ferramentas de um programador de projetos mentais.
Ações como ler dados de arquivos, trabalhando com loops e trocar os valores de duas variáveis são bons exemplos. O programador saberá pelo menos uma maneira de alcançar suas extremidades em uma forma genérica ou de baunilha. Talvez isso seja suficiente para a exigência de mãos. Ou talvez eles embelem o código para torná-lo mais eficiente ou aplicável à solução específica que estão se desenvolvendo. Mas ter o idioma de bloco de construção na ponta dos dedos é um ótimo ponto de partida.
Saber e entender idiomas em uma língua torna mais fácil pegar uma nova linguagem de programação. Sabendo como as coisas são construídas em uma língua e procurando o equivalente - ou a coisa mais próxima - em outra linguagem é uma boa maneira de apreciar as semelhanças e diferenças entre as linguagens de programação que você já conhece e aquela que você está aprendendo.
Linhas de leitura de um arquivo: o um-liner
Em Bash, você pode usar um
enquanto
Loop na linha de comando para ler cada linha de texto de um arquivo e fazer algo com ele. Nosso arquivo de texto é chamado "Data.txt". Ele detém uma lista dos meses do ano.
janeiro fevereiro marchar . . Outubro novembro Dezembro
Nosso simples um liner é:
enquanto a linha de leitura; Faça Echo $ Line; feito e lt; data.txt
o
enquanto
Loop lê uma linha do arquivo, e o fluxo de execução do pequeno programa passa para o corpo do loop. o
eco
O comando grava a linha de texto na janela do terminal. A tentativa de leitura falha quando não há mais linhas a serem lidas e o loop é feito.
Um truque limpo é a capacidade Para redirecionar um arquivo em um loop . Em outras linguagens de programação, você precisaria abrir o arquivo, lido dele e fechá-lo novamente quando terminar. Com Bash, você pode simplesmente usar o redirecionamento de arquivos e deixar o shell lidar com todas essas coisas de baixo nível para você.
Claro, este um revestimento não é terrivelmente útil. O Linux já fornece o
gato
comando, que faz exatamente isso para nós. Criamos uma maneira clara de substituir um comando de três letras. Mas demonstra visivelmente os princípios de leitura de um arquivo.
Isso funciona bem o suficiente, até certo ponto. Suponha que tenhamos outro arquivo de texto que contenha os nomes dos meses. Neste arquivo, a sequência de escape para um caractere de nova linha foi anexada a cada linha. Vamos chamá-lo de "data2.txt".
janeiro \ n Fevereiro \ n. Março \ n. . . Outubro \ n. Novembro \ n. Dezembro \ n
Vamos usar nosso one-liner no nosso novo arquivo.
enquanto a linha de leitura; Faça Echo $ Line; feito e lt; Data2.txt
O personagem de escape backsash "
\
"Foi descartado. O resultado é que um "N" foi anexado a cada linha. Bash está interpretando a barra invertida como o início de um
sequência de fuga
. Muitas vezes, não queremos que Bash interpreta o que está lendo. Pode ser mais conveniente ler uma linha em suas seqüências de escape de barragem portuguesa e tudo - e escolha o que para analisar ou substituir-se, dentro do seu próprio código.
Se quisermos fazer qualquer processamento significativo ou analisar as linhas de texto, precisaremos usar um script.
Linhas de leitura de um arquivo com um script
Aqui está o nosso roteiro. É chamado de "script1.sh".
#! / Bin / bash
Contador = 0
Enquanto ifs = '' Leia -r linefromfile [116 ] || [ -n " $ {linefromfile} ] ]; Do
( contador ++ ))
ECHO "Acessando a linha $ contador : $ {linefromfile} ]
feito & lt; " $ 1 "
Nós definimos uma variável chamada
Contador
para zero, então definimos nosso
enquanto
ciclo.
A primeira declaração na linha enquanto é
Ifs = ''
.
Ifs.
significa separador de campo interno. Ele detém valores que bash usam para identificar limites de palavras. Por padrão, o comando lido tire liderando e à direita espaço em branco. Se quisermos ler as linhas do arquivo exatamente como eles são, precisamos definir
Ifs.
para ser uma corda vazia.
Poderíamos definir isso uma vez fora do loop, assim como estamos estabelecendo o valor de
Contador
. Mas com scripts mais complexos - especialmente aqueles com muitas funções definidas pelo usuário nelas - é possível que
Ifs.
poderia ser definido para valores diferentes em outro lugar no script. Garantindo isso
Ifs.
é definido para uma string vazia toda vez que o
enquanto
Loop iteraates garante que sabemos qual será o seu comportamento.
Nós vamos ler uma linha de texto em uma variável chamada
Linefromfile.
. Estamos usando o.
-r.
(Leia Backslash como uma opção de caractere normal) para ignorar barras invertidas. Eles serão tratados como qualquer outro personagem e não receberão nenhum tratamento especial.
Existem duas condições que satisfarão o
enquanto
Loop e permitir que o texto seja processado pelo corpo do loop:
-
leia -r linefromfile.: Quando uma linha de texto é lida com sucesso a partir do arquivo, oleituraComando envia um sinal de sucesso para oenquanto, e asenquantoLoop passa o fluxo de execução para o corpo do loop. Note que o.leituracomando precisa ver um Personagem Newline. no final da linha de texto, a fim de considerá-lo uma leitura bem-sucedida. Se o arquivo não for um Posix. Arquivo de texto compatível, o A última linha pode não incluir um caractere newline . Se o.leituracomando vê o. Fim do marcador de arquivos (EOF) antes que a linha seja terminada por uma nova linha, não Trate-o como uma leitura bem sucedida. Se isso acontecer, a última linha de texto não será passada para o corpo do loop e não será processada. -
[-n "$ {linefromfile}"]: Precisamos fazer algum trabalho extra para lidar com arquivos compatíveis não posterix. Esta comparação verifica o texto que é lido do arquivo. Se não for encerrado com um caractere newline, essa comparação ainda retornará sucesso aoenquantociclo. Isso garante que qualquer fragmento de linha de fuga seja processado pelo corpo do loop.
Essas duas cláusulas são separadas pelo operador ou lógico "
||.
"Então, se
qualquer
A cláusula retorna o sucesso, o texto recuperado é processado pelo corpo do loop, se há um caractere de nova linha ou não.
No corpo do nosso loop, estamos incrementando o
Contador
variável por um e usando
eco
para enviar alguma saída para a janela do terminal. O número da linha e o texto de cada linha são exibidos.
Ainda podemos usar nosso truque de redirecionamento para redirecionar um arquivo em um loop. Nesse caso, estamos redirecionando US $ 1, uma variável que mantém o nome do primeiro parâmetro de linha de comando que passou para o script. Usando este truque, podemos facilmente passar no nome do arquivo de dados que queremos que o script funcione.
Copie e cole o script em um editor e salve-o com o nome do arquivo "script1.sh." Use o
chmod.
comando
para tornar isso executável
.
chmod + x script1.sh
Vamos ver o que nosso script faz do arquivo de texto data2.txt e as barras invertidas contidas dentro dela.
./ script1.sh data2.txt
Cada personagem na linha é exibido verbatim. As barras traseiras não são interpretadas como personagens de escape. Eles são impressos como caracteres regulares.
Passando a linha para uma função
Ainda estamos apenas ecoando o texto para a tela. Em um cenário de programação do mundo real, provavelmente estaríamos prestes a fazer algo mais interessante com a linha de texto. Na maioria dos casos, é uma boa prática de programação para lidar com o processamento adicional da linha em outra função.
Veja como poderíamos fazer isso. Isso é "script2.sh".
Nós definimos nosso
Contador
variável como antes, e depois definimos uma função chamada
Process_line ()
. A definição de uma função deve aparecer
antes
A função é chamada primeiro no script.
Nossa função vai ser passada na recém-lida linha de texto em cada iteração do
enquanto
ciclo. Podemos acessar esse valor dentro da função usando o
$ 1.
variável. Se houvesse duas variáveis passadas para a função, poderíamos acessar esses valores usando
$ 1.
e
$ 2.
e assim por diante para mais variáveis.
O W
hile
loop é principalmente o mesmo. Há apenas uma mudança dentro do corpo do loop. o
eco
linha foi substituída por uma chamada para o
Process_line ()
função. Observe que você não precisa usar os colchetes "()" em nome da função quando estiver chamando.
O nome da variável segurando a linha de texto,
Linefromfile.
, é envolto em aspas quando é passado para a função. Isso atende por linhas que têm espaços neles. Sem as aspas, a primeira palavra é tratada como
$ 1.
pela função, a segunda palavra é considerada como sendo
$ 2.
, e assim por diante. Usar aspas assegura que toda a linha de texto seja tratada,
$ 1.
. Note que isso é
não
o mesmo
$ 1.
que detém o mesmo arquivo de dados passado para o script.
Porque
Contador
foi declarado no corpo principal do roteiro e não dentro de uma função, pode ser referenciado dentro do
Process_line ()
função.
Copie ou digite o script acima em um editor e salve-o com o nome do arquivo "script2.sh." Torná-lo executável com
chmod.
:
chmod + x script2.sh
Agora podemos executá-lo e passar em um novo arquivo de dados, "Data3.txt". Isso tem uma lista dos meses e uma linha com muitas palavras nele.
janeiro fevereiro marchar . . Outubro Novembro \ nmore texto "no final da linha" Dezembro
Nosso comando é:
./ script2.sh data3.txt
As linhas são lidas do arquivo e passou um por um para o
Process_line ()
função. Todas as linhas são exibidas corretamente, incluindo o estranho com o backspace, aspas e várias palavras nele.
Blocos de construção são úteis
Há um trem de pensamento que diz que um idioma deve conter algo único para essa linguagem. Isso não é uma crença de que me inscrevo. O importante é que ele faz o bom uso da linguagem, é fácil de lembrar e fornece uma maneira confiável e robusta de implementar alguma funcionalidade em seu código.