uto*_*man 7 unix compilation pipe broken-pipe rust
我在铁锈中有这样的痕迹:
\n\nthread \'main\' panicked at \'failed printing to stdout: Broken pipe (os error 32)\', library/std/src/io/stdio.rs:993:9\nstack backtrace:\n 0: 0x559ffa959dc0 - std::backtrace_rs::backtrace::libunwind::trace::h72c2fb8038f1bbee\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/../../backtrace/src/backtrace/libunwind.rs:96\n 1: 0x559ffa959dc0 - std::backtrace_rs::backtrace::trace_unsynchronized::h1e3b084883f1e78c\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/../../backtrace/src/backtrace/mod.rs:66\n 2: 0x559ffa959dc0 - std::sys_common::backtrace::_print_fmt::h3bf6a7ebf7f0394a\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/sys_common/backtrace.rs:79\n 3: 0x559ffa959dc0 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h2e8cb764b7fe02e7\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/sys_common/backtrace.rs:58\n 4: 0x559ffa972f6c - core::fmt::write::h7a1184eaee6a8644\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/fmt/mod.rs:1080\n 5: 0x559ffa957b12 - std::io::Write::write_fmt::haeeb374d93a67eac\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/io/mod.rs:1516\n 6: 0x559ffa95beed - std::sys_common::backtrace::_print::h1d14a7f6ad632dc8\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/sys_common/backtrace.rs:61\n 7: 0x559ffa95beed - std::sys_common::backtrace::print::h301abac8bb2e3e81\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/sys_common/backtrace.rs:48\n 8: 0x559ffa95beed - std::panicking::default_hook::{{closure}}::hde0cb80358a6920a\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/panicking.rs:208\n 9: 0x559ffa95bb98 - std::panicking::default_hook::h9b1a691049a0ec8f\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/panicking.rs:227\n 10: 0x559ffa95c5d1 - std::panicking::rust_panic_with_hook::h2bdec87b60580584\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/panicking.rs:577\n 11: 0x559ffa95c179 - std::panicking::begin_panic_handler::{{closure}}::h101ca09d9df5db47\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/panicking.rs:484\n 12: 0x559ffa95a22c - std::sys_common::backtrace::__rust_end_short_backtrace::h3bb85654c20113ca\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/sys_common/backtrace.rs:153\n 13: 0x559ffa95c139 - rust_begin_unwind\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/panicking.rs:483\n 14: 0x559ffa95c0eb - std::panicking::begin_panic_fmt::hf0503558fbe5b251\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/panicking.rs:437\n 15: 0x559ffa957022 - std::io::stdio::print_to::h9435376f36962f3f\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/io/stdio.rs:993\n 16: 0x559ffa957022 - std::io::stdio::_print::h0d31d4b9faa6e1ec\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/io/stdio.rs:1005\n 17: 0x559ffa944807 - wordstats::main::h1c2ea6400047a5eb\n 18: 0x559ffa942e73 - std::sys_common::backtrace::__rust_begin_short_backtrace::h9e31cf87ddc88116\n 19: 0x559ffa942e49 - std::rt::lang_start::{{closure}}::h6c6491f05894818f\n 20: 0x559ffa95c9f7 - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::he179d32a5d10d957\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/ops/function.rs:259\n 21: 0x559ffa95c9f7 - std::panicking::try::do_call::hcb3d5e7be089b2b4\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/panicking.rs:381\n 22: 0x559ffa95c9f7 - std::panicking::try::h7ac93b0cd56fb701\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/panicking.rs:345\n 23: 0x559ffa95c9f7 - std::panic::catch_unwind::h7b40e396c93a4fcd\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/panic.rs:382\n 24: 0x559ffa95c9f7 - std::rt::lang_start_internal::h142b9cc66267fea1\n at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/rt.rs:51\n 25: 0x559ffa944ae2 - main\n 26: 0x7f6223a380b3 - __libc_start_main\n 27: 0x559ffa94209e - _start\n 28: 0x0 - <unknown>\n\nRun Code Online (Sandbox Code Playgroud)\n当我编译这个程序时
\nuse diacritics;\nuse std::collections::HashMap;\nuse std::io;\nuse std::io::prelude::*;\n\n#[derive(Debug)]\nstruct Entry {\n word: String,\n count: u32,\n}\n\nstatic SEPARATORS: &\'static [char] = &[\n \' \', \',\', \'.\', \'!\', \'?\', \'\\\'\', \'"\', \'\\n\', \'(\', \')\', \'#\', \'{\', \'}\', \'[\', \']\', \'-\', \';\', \':\',\n];\n\nfn main() {\n let mut words: HashMap<String, u32> = HashMap::new();\n let stdin = io::stdin();\n for line in stdin.lock().lines() {\n line_processor(line.unwrap(), &mut words)\n }\n output(&mut words);\n}\n\nfn line_processor(line: String, words: &mut HashMap<String, u32>) {\n let formatted_line;\n let mut word = String::new();\n formatted_line = diacritics::remove_diacritics(&line).to_lowercase();\n\n for c in formatted_line.chars() {\n if SEPARATORS.contains(&c) {\n add_word(word, words);\n word = String::new();\n } else {\n word.push_str(&c.to_string());\n }\n }\n}\n\nfn add_word(word: String, words: &mut HashMap<String, u32>) {\n if word.len() > 0 {\n if words.contains_key::<str>(&word) {\n words.insert(word.to_string(), words.get(&word).unwrap() + 1);\n } else {\n words.insert(word.to_string(), 1);\n }\n // println!("word >{}<", word.to_string())\n }\n}\n\nfn output(words: &mut HashMap<String, u32>) {\n let mut stack = Vec::<Entry>::new();\n\n for (k, v) in words {\n stack.push(Entry {\n word: k.to_string(),\n count: *v,\n });\n }\n\n stack.sort_by(|a, b| b.count.cmp(&a.count));\n stack.reverse();\n\n while let Some(entry) = stack.pop() {\n println!("{}\\t{}", entry.count, entry.word);\n }\n}\n\nRun Code Online (Sandbox Code Playgroud)\n这边走 :
\ncargo build --release\nRun Code Online (Sandbox Code Playgroud)\n我这样运行程序:
\ncargo build --release\nRun Code Online (Sandbox Code Playgroud)\n这个程序应该只显示类似这样的内容(最高字数),没有任何痕迹:
\ncat src/sample.txt | ./target/release/wordstats | head -n 50\nRun Code Online (Sandbox Code Playgroud)\n这是一些回显内容或一些其他文件(例如)的情况cat src/main.rs | ...\n但不适用于作为随机维基百科页面一部分的此文件内容。
我的程序是一个愚蠢的字数统计程序,仅打印表格排序的键值列表。
\n当我在程序中通过管道传输结果时会出现此问题,head -n 50但在打印完整输出时不会出现此问题
知道为什么我会得到这样的痕迹吗?我在程序中处理某些问题的方式是否错误,或者是否与其他问题有关(rust lib / unix 不当行为)
\n我的 rustc 版本是:rustc 1.48.0 (7eac88abb 2020-11-16)
编辑 :
\n添加缺少的 Cargo.toml
\n[package]\nname = "wordstats"\nversion = "0.1.0"\nauthors = ["Eric R\xc3\xa9gnier <utopman@gmail.com>"]\nedition = "2018"\n\n[dependencies]\ndiacritics = "0.1.1"\nRun Code Online (Sandbox Code Playgroud)\n
Bur*_*hi5 12
首先,您没有提供足够的信息来重现您的问题。您提供了使用第三方依赖项的源代码,但忽略了提供Cargo.toml. 就您而言,删除依赖项的使用非常容易,而不会影响手头的问题,所以这就是我所做的。
其次,println!正是由于这个原因,在非玩具命令行程序中使用是一把枪。也就是说,有两个问题结合在一起会产生这种不良行为:
println!如果写入标准输出时发生任何错误,将会出现恐慌。PIPE已关闭的文件描述符的相应写入将返回错误,而不是向您的应用程序发送信号。(在该链接中,您可以看到我记录在案,主张改变这种行为。)在典型的 C 程序中,SIGPIPE不会被忽略。通常也不会明确处理它。当进程收到一个它无法处理的信号时,该进程就会终止。在这种情况下,这正是您想要的。一旦head停止读取其标准输入(您的标准输出),您希望程序停止,但您也希望它优雅地停止,而不会惊慌或打印错误。因为这就是 Unix CLI 实用程序的作用。
您有两种方法可以解决这个问题。一种方法是更改代码以BrokenPipe显式处理错误。您的代码的编写方式就好像错误不会发生一样,因为您是unwrap读取标准输出的结果。所以你的程序不符合习惯,也没有设置来处理错误。因此,为了BrokenPipe正确处理,我必须进行一些小更改,以便它正确地冒出错误:
use std::collections::HashMap;
use std::io;
use std::io::prelude::*;
#[derive(Debug)]
struct Entry {
word: String,
count: u32,
}
static SEPARATORS: &'static [char] = &[
' ', ',', '.', '!', '?', '\'', '"', '\n', '(', ')', '#', '{', '}', '[', ']', '-', ';', ':',
];
fn main() {
if let Err(err) = try_main() {
if err.kind() == std::io::ErrorKind::BrokenPipe {
return;
}
// Ignore any error that may occur while writing to stderr.
let _ = writeln!(std::io::stderr(), "{}", err);
}
}
fn try_main() -> Result<(), std::io::Error> {
let mut words: HashMap<String, u32> = HashMap::new();
let stdin = io::stdin();
for result in stdin.lock().lines() {
let line = result?;
line_processor(line, &mut words)
}
output(&mut words)?;
Ok(())
}
fn line_processor(line: String, words: &mut HashMap<String, u32>) {
let mut word = String::new();
for c in line.chars() {
if SEPARATORS.contains(&c) {
add_word(word, words);
word = String::new();
} else {
word.push_str(&c.to_string());
}
}
}
fn add_word(word: String, words: &mut HashMap<String, u32>) {
if word.len() > 0 {
if words.contains_key::<str>(&word) {
words.insert(word.to_string(), words.get(&word).unwrap() + 1);
} else {
words.insert(word.to_string(), 1);
}
// println!("word >{}<", word.to_string())
}
}
fn output(words: &mut HashMap<String, u32>) -> Result<(), std::io::Error> {
let mut stack = Vec::<Entry>::new();
for (k, v) in words {
stack.push(Entry {
word: k.to_string(),
count: *v,
});
}
stack.sort_by(|a, b| b.count.cmp(&a.count));
stack.reverse();
let stdout = io::stdout();
let mut stdout = stdout.lock();
while let Some(entry) = stack.pop() {
writeln!(stdout, "{}\t{}", entry.count, entry.word)?;
}
Ok(())
}
Run Code Online (Sandbox Code Playgroud)
处理此问题的第二种方法是返回到 的默认行为SIGPIPE。这将使您的 Rust 应用程序表现得像 C 应用程序。SIGPIPE这可以通过定义一个函数来重置to的信号处理程序来完成SIG_DFL:
#[cfg(unix)]
fn reset_sigpipe() {
unsafe {
libc::signal(libc::SIGPIPE, libc::SIG_DFL);
}
}
#[cfg(not(unix))]
fn reset_sigpipe() {
// no-op
}
Run Code Online (Sandbox Code Playgroud)
然后将其称为 中的第一件事main。然后您可以删除对BrokenPipe错误的任何特定处理,因为它不会发生。相反,您的进程将收到一个PIPE信号,并且随后将终止。这是完整的代码:
use std::collections::HashMap;
use std::io;
use std::io::prelude::*;
#[derive(Debug)]
struct Entry {
word: String,
count: u32,
}
static SEPARATORS: &'static [char] = &[
' ', ',', '.', '!', '?', '\'', '"', '\n', '(', ')', '#', '{', '}', '[', ']', '-', ';', ':',
];
fn main() {
if let Err(err) = try_main() {
let _ = writeln!(std::io::stderr(), "{}", err);
}
}
fn try_main() -> Result<(), std::io::Error> {
reset_sigpipe();
let mut words: HashMap<String, u32> = HashMap::new();
let stdin = io::stdin();
for result in stdin.lock().lines() {
let line = result?;
line_processor(line, &mut words)
}
output(&mut words)?;
Ok(())
}
fn line_processor(line: String, words: &mut HashMap<String, u32>) {
let mut word = String::new();
for c in line.chars() {
if SEPARATORS.contains(&c) {
add_word(word, words);
word = String::new();
} else {
word.push_str(&c.to_string());
}
}
}
fn add_word(word: String, words: &mut HashMap<String, u32>) {
if word.len() > 0 {
if words.contains_key::<str>(&word) {
words.insert(word.to_string(), words.get(&word).unwrap() + 1);
} else {
words.insert(word.to_string(), 1);
}
// println!("word >{}<", word.to_string())
}
}
fn output(words: &mut HashMap<String, u32>) -> Result<(), std::io::Error> {
let mut stack = Vec::<Entry>::new();
for (k, v) in words {
stack.push(Entry {
word: k.to_string(),
count: *v,
});
}
stack.sort_by(|a, b| b.count.cmp(&a.count));
stack.reverse();
let stdout = io::stdout();
let mut stdout = stdout.lock();
while let Some(entry) = stack.pop() {
writeln!(stdout, "{}\t{}", entry.count, entry.word)?;
}
Ok(())
}
#[cfg(unix)]
fn reset_sigpipe() {
unsafe {
libc::signal(libc::SIGPIPE, libc::SIG_DFL);
}
}
#[cfg(not(unix))]
fn reset_sigpipe() {
// no-op
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1684 次 |
| 最近记录: |