Rust Pills - Agindo como um filtro unix
Nesta dica será apresentada uma forma de ler a entrada padrão (stdin
), em um programa Rust.
Há problemas em que é mais simples ler a entrada padrão, processar e mostrar alguma saída. Bem mais prático que receber o nome de um arquivo como parâmetro, abrir o arquivo, ler o arquivo, processar e então mostrar a saída.
Pipes são uma facilidade muito presente no mundo Unix.
Eu me bati um pouco pra conseguir isso, e talvez essa não seja a melhor solução, mas faz o trabalho. Ler a entrada padrão (stdin) e escrever para saída padrão (stdout):
use std::io;
use std::io::prelude::*;
fn main() {
let stdin = io::stdin();
for l in stdin.lock().lines() {
let line = l.unwrap();
println!("{}", line);
}
}
A linha duas primeiras linhas nos permitem ter acesso ao que precisamos para processar a entrada padrão. Dentro do main
, criamos um handler para a entrada padrão (stdin
). e logo após, no for
lemos linha a linha.
Ao compilar e executar (salvei como cat.rs), temos isso:
$ rustc cat.rs
$ ls /|./cat
bin
boot
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
Se não passar nenhum "fluxo" para o comando, ele irá imprimir o que você digitar, até que sejam digitadas as teclas CONTROL
e D
.
Mas no meu problema concreto, eu devo ler cada linha, executar um processamento, e se uma condição for satisfeita, imprimir a linha e o resultado do processamento.
Aí a coisa pegou.
Pois no Rust, uma vez que um conteúdo é "consumido", ele não existe mais. E é isso que acontecia no meu problema, pois eu precisa passar a linha como um vetor de u8 para minha função de processamento, e ao fazer essa conversão, eu não tinha mais acesso à linha.
Mas depois de algumas releituras do manual, da documentação, de artigos e tutoriais, cheguei a esse resultado:
use std::io;
use std::io::prelude::*;
fn begin_with_b(array: &[u8]) -> bool {
array[0] as char == 'b'
}
fn main() {
let stdin = io::stdin();
for l in stdin.lock().lines() {
let line = l.unwrap();
let bytes = line.as_bytes();
if begin_with_b(bytes) {
println!("{}", line);
}
}
}
Executando (salvei como filter.rs
):
$ rustc filter.rs
$ ls /|./filter
bin
boot