diff --git a/src/sed/compiler.rs b/src/sed/compiler.rs index bcfff31..3665a38 100644 --- a/src/sed/compiler.rs +++ b/src/sed/compiler.rs @@ -1348,7 +1348,7 @@ fn get_cmd_spec( n_addr: 2, handler: compile_subst_command, }), - 'w' => Ok(CommandSpec { + 'w' | 'W' if !posix => Ok(CommandSpec { n_addr: 2, handler: compile_write_file_command, }), diff --git a/src/sed/processor.rs b/src/sed/processor.rs index 45d6b26..934969a 100644 --- a/src/sed/processor.rs +++ b/src/sed/processor.rs @@ -607,6 +607,15 @@ fn process_file( let writer = extract_variant!(command, NamedWriter); writer.borrow_mut().write_line(pattern.as_str()?)?; } + 'W' => { + // Append only the first line of the pattern space. + let writer = extract_variant!(command, NamedWriter); + let pattern_text = pattern.as_str()?; + let line = pattern_text + .split_once('\n') + .map_or(pattern_text, |(first_line, _)| first_line); + writer.borrow_mut().write_line(line)?; + } 'x' => { // Exchange the contents of the pattern and hold spaces. let (pat_content, pat_has_newline) = pattern.fields_mut()?; diff --git a/tests/by-util/test_sed.rs b/tests/by-util/test_sed.rs index b31fed7..202e6b7 100644 --- a/tests/by-util/test_sed.rs +++ b/tests/by-util/test_sed.rs @@ -818,6 +818,32 @@ fn write_two_files() -> std::io::Result<()> { Ok(()) } +#[test] +fn write_first_line_with_w_command() -> std::io::Result<()> { + let temp = NamedTempFile::new()?; + let cmd = format!("N;W {}", temp.path().display()); + + new_ucmd!() + .args(&["-n", "-e", &cmd]) + .pipe_in("abc\ndef\n") + .succeeds(); + + let mut actual = String::new(); + temp.reopen()?.read_to_string(&mut actual)?; + assert_eq!(actual, "abc\n"); + + Ok(()) +} + +#[test] +fn write_first_line_with_w_command_is_non_posix() { + new_ucmd!() + .args(&["--posix", "W /tmp/out"]) + .fails() + .code_is(1) + .stderr_is("sed: