rust - Cómo enviar salida a stderr
stdio (5)
Después de Rust 1.19
A partir de Rust 1.19, puede usar las macros eprint
y eprintln
:
fn main() {
eprintln!("This is going to standard error!, {}", "awesome");
}
Esto fue propuesto originalmente en RFC 1896 .
Antes de Rust 1.19
¡Puedes ver la implementación de println!
sumergirse en exactamente cómo funciona, pero fue un poco abrumador cuando lo leí por primera vez.
Sin embargo, puede formatear cosas en stderr usando macros similares:
use std::io::Write;
let name = "world";
writeln!(&mut std::io::stderr(), "Hello {}!", name);
Esto le dará un unused result which must be used
, ya que la impresión en IO puede fallar (¡esto no es algo que normalmente pensamos al imprimir!). Podemos ver que los métodos existentes simplemente entran en pánico en este caso, por lo que podemos actualizar nuestro código para hacer lo mismo:
use std::io::Write;
let name = "world";
let r = writeln!(&mut std::io::stderr(), "Hello {}!", name);
r.expect("failed printing to stderr");
Esto es demasiado, así que vamos a envolverlo en una macro:
use std::io::Write;
macro_rules! println_stderr(
($($arg:tt)*) => { {
let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
r.expect("failed printing to stderr");
} }
);
fn main() {
let name = "world";
println_stderr!("Hello {}!", name)
}
Uno lo usa para enviar salida a stdout:
println!("some output")
Creo que no hay macro correspondiente para hacer lo mismo para stderr.
Gol
stderr!("Code {}: Danger, Will Robinson! Danger!", 42);
Notas
Las otras respuestas generan una advertencia de importación no utilizada con la última noche, por lo que aquí hay una macro moderna que Just Works TM.
Código
macro_rules! stderr {
($($arg:tt)*) => (
use std::io::Write;
match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
Ok(_) => {},
Err(x) => panic!("Unable to write to stderr (file handle closed?): {}", x),
}
)
}
Está hecho así:
use std::io::Write;
fn main() {
std::io::stderr().write(b"some output/n");
}
Puede probarlo enviando la salida del programa a /dev/null
para garantizar que funcione (ignoro la advertencia):
$ rustc foo.rs && ./foo > /dev/null
foo.rs:4:5: 4:42 warning: unused result which must be used, #[warn(unused_must_use)] on by default
foo.rs:4 io::stderr().write(b"some output/n");
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
some output
Del mismo modo, uno puede hacer lo siguiente para stdout:
use std::io::Write;
fn main() {
std::io::stdout().write(b"some output/n");
}
¡Creo que esto significa println!
es solo una conveniencia: es más corta y también permite algún formato. Como ejemplo de esto último, lo siguiente muestra 0x400
:
println!("0x{:x}", 1024u)
Si bien no responde la pregunta precisa, tal vez sea interesante que exista una caja de log
que especifique una interfaz para el registro nivelado que otras cajas (por ejemplo, env_logger
) puedan cumplir.
La salida de dicho registro se enviará a stderr
, y hay beneficios adicionales para los usuarios, como especificar el nivel de registro.
Así es como usar un registrador así podría ser:
#[macro_use]
extern crate log;
extern crate env_logger;
fn main() {
env_logger::init().unwrap();
error!("this is printed by default");
}
(Ejemplo adaptado de http://burntsushi.net/rustdoc/env_logger/index.html#example )
print!
y println!
son métodos de conveniencia para escribir en la salida estándar. Hay otras macros con las mismas funciones de formato disponibles para diferentes tareas:
-
write!
ywriteln!
escribir una cadena formateada en un&mut Writer
-
format!
para generar unaString
formateada
Para escribir en el flujo de error estándar, puede usar, por ejemplo, writeln!
Me gusta esto:
use std::io::Write;
fn main() {
let mut stderr = std::io::stderr();
writeln!(&mut stderr, "Error!").unwrap();
}