Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does "sed -n -i" delete existing file contents?

Tags:

sed

gnu-sed

Running Fedora 25 server edition. sed --version gives me sed (GNU sed) 4.2.2 along with the usual copyright and contact info. I've create a text file sudo vi ./potential_sed_bug. Vi shows the contents of this file (with :set list enabled) as:

don't$
delete$
me$
please$

I then run the following command:

sudo sed -n -i.bak /please/a\testing ./potential_sed_bug

Before we discuss the results; here is what the sed man page says:

-n, --quiet, --silent suppress automatic printing of pattern space

and

-i[SUFFIX], --in-place[=SUFFIX] edit files in place (makes backup if extension supplied). The default operation mode is to break symbolic and hard links. This can be changed with --follow-symlinks and --copy.

I've also looked other sed command references to learn how to append with sed. Based on my understanding from the research I've done; the resulting file content should be:

don't
delete
me
please
testing

However, running sudo cat ./potential_sed_bug gives me the following output:

testing

In light of this discrepancy, is my understanding of the command I ran incorrect or is there a bug with sed/the environment?

like image 965
AMemberofDollars Avatar asked Mar 07 '17 01:03

AMemberofDollars


People also ask

Can we delete content in a file by using sed command?

Sed Command to Delete Lines: Sed command can be used to delete or remove specific lines which matches a given pattern or in a particular position in a file. Here we will see how to delete lines using sed command with various examples.

How do you delete a line in a file using sed?

To delete a line, we'll use the sed “d” command. Note that you have to declare which line to delete. Otherwise, sed will delete all the lines.

What does the sed command do?

SED is a text stream editor used on Unix systems to edit files quickly and efficiently. The tool searches through, replaces, adds, and deletes lines in a text file without opening the file in a text editor. Learn how to use the sed command and its options through easy-to-follow examples.

How do I remove a specific pattern from a Unix file?

N command reads the next line in the pattern space. d deletes the entire pattern space which contains the current and the next line. Using the substitution command s, we delete from the newline character till the end, which effective deletes the next line after the line containing the pattern Unix.


1 Answers

tl;dr

  • Don't use -n with -i: unless you use explicit output commands in your sed script, nothing will be written to your file.

  • Using -i produces no stdout (terminal) output, so there's nothing extra you need to do to make your command quiet.


By default, sed automatically prints the (possibly modified) input lines to whatever its output target is, whether implied or explicitly specified: by default, to stdout (the terminal, unless redirected); with -i, to a temporary file that ultimately replaces the input file.

In both cases, -n suppresses this automatic printing, so that - unless you use explicit output functions such as p or, in your case, a - nothing gets printed to stdout / written to the temporary file.

  • Note that the automatic printing applies to the so-called pattern space, which is where the (possibly modified) input is held; explicit output functions such as p, a, i and c do not print to the pattern space (for potential subsequent modification), they print directly to the target stream / file, which is why a\testing was able to produce output, despite the use of -n.

Note that with -i, sed's implicit printing / explicit output commands only print to the temporary file, and not also to stdout, so a command using -i is invariably quiet with respect to stdout (terminal) output - there's nothing extra you need to do.


To give a concrete example (GNU sed syntax).

Since the use of -i is incidental to the question, I've omitted it for simplicity. Note that -i prints to a temporary file first, which, on completion, replaces the original. This comes with pitfalls, notably the potential destruction of symlinks; see the lower half of this answer of mine.

# Print input (by default), and append literal 'testing' after 
# lines that contain 'please'.
$ sed '/please/ a testing' <<<$'yes\nplease\nmore'
yes
please
testing
more

# Adding `-n` suppresses the default printing, so only `testing` is printed.
# Note that the sequence of processing is exactly the same as without `-n`:
# If and when a line with 'please' is found, 'testing' is appended *at that time*.
$ sed -n '/please/ a testing' <<<$'yes\nplease\nmore'
testing

# Adding an unconditional `p` (print) call undoes the effect of `-n`.
$ sed -n 'p; /please/ a testing' <<<$'yes\nplease\nmore'
yes
please
testing
more
like image 159
mklement0 Avatar answered Oct 05 '22 17:10

mklement0