简体   繁体   中英

Why does sed add a new line in OSX?

echo -n 'I hate cats' > cats.txt
sed -i '' 's/hate/love/' cats.txt

This changes the word in the file correctly, but also adds a newline to the end of the file. Why? This only happens in OSX, not Ubuntu etc. How can I stop it?

echo -n 'I hate cats' > cats.txt

This command will populate the contents of 'cats.txt' with the 11 characters between the single quotes. If you check the size of cats.txt at this stage it should be 11 bytes.

sed -i '' 's/hate/love/' cats.txt

This command will read the cats.txt file line by line , and replace it with a file where each line has had the first instance of 'hate' replaced by 'love' (if such an instance exists). The important part is understanding what a line is. From the sed man page:

 Normally, sed cyclically copies a line of input, not including its
 terminating newline character, into a pattern space, (unless there is
 something left after a ``D'' function), applies all of the commands
 with addresses that select that pattern space, copies the pattern
 space to the standard output, appending a newline, and deletes the
 pattern space.

Note the appending a newline part. On your system, sed is still interpreting your file as containing a single line, even though there is no terminating newline. So the output will be the 11 characters, plus the appended newline. On other platforms this would not necessarily be the case. Sometimes sed will completely skip the last line in a file (effectively deleting it) because it is not really a line ! But in your case, sed is basically fixing the file for you (as a file with no lines in it, it is broken input to sed).

See more details here: Why should text files end with a newline?

See this question for an alternate approach to your problem: SED adds new line at the end

If you need a solution which will not add the newline, you can use gsed ( brew install gnu-sed )

A good way to avoid this problem is to use perl instead of sed. Perl will respect the EOF newline, or lack thereof, that is in the original file.

echo -n 'I hate cats' > cats.txt
perl -pi -e 's/hate/love/' cats.txt

请注意,GNU sed不会在Mac OS上添加换行符。

Another thing you can do is this:

echo -n 'I hate cats' > cats.txt
SAFE=$(cat cats.txt; echo x)
SAFE=$(printf "$SAFE" | sed -e 's/hate/love/')
SAFE=${SAFE%x}

That way if cats.txt ends in a newline it gets preserved. If it doesn't, it doesn't get one added on.

This worked for me. I didn't have to use an intermediate file.

OUTPUT=$( echo 'I hate cats' | sed 's/hate/love/' )
echo -n "$OUTPUT"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM