awk Command to add Carriage Return and Line Feed

Hello,

Can someone please share a Simple AWK command to append Carriage Return & Line Feed to the end of the file, If the Carriage Return & Line Feed does not exist !

Thanks

awk is not a good language for that, being it's not guaranteed to work at all on unterminated lines.

What have you tried?

Hi,

I tried this , I am using cat command which is not efficient

cat source.txt | sed 's/[^[:print:]\r\t]//g' | perl -lpe 's/\x0d$//' > output.txt

Why not the sed version?

sed '/\r$/!s/$/\r/' source.txt

or

sed 's/\r*$/\r/' source.txt
1 Like

With awk, try:

awk '{sub(/\r?$/,"\r")}1' file

--
Note: With sed, the use of \r with the s command is not standard, it is GNU sed only.

1 Like

Unix text files have only a linefeed character to indicate a newline.
Perhaps you mean "add a missing linefeed to the end of the file"?
The consider this shell script

#!/bin/sh
# append a missing last newline
prtstdin(){
  while IFS= read line; do echo "$line"; done
  [ -z "$line" ]] || echo "$line"
}
if [ $# -eq 0 ]
then
  prtstdin
else
  for arg
  do
    prtstdin  <"$arg"
  done
fi

The script can be used like the "cat" program.

Why not use the unix2dos and dos2unix programs or (more generally) recode ? They were explicitly designed for the job you (mis-)use other innocent programs for.

I hope this helps.

bakunin

Neither awk nor sed have defined behavior according to the standards if the file being processed is not a text file. If an input file contains any characters and the last character in the file is not a <newline> character, that input file is not a text file. (So the code Scrutinizer suggested also depends on GNU extensions to awk that are not portable and not required by the standards.)

Assuming that all lines in your file are separated by DOS <carriage-return><newline> line separators and you just want to add a <carriage-return><newline> terminator to the last line of a file if it doesn't already exist, and assuming that an empty input file should produce an empty output file (not adding a DOS format empty line), the following POSIX-conforming shell script should be portable to most systems:

{ cat "${1:-file}"; printf '\r\n'; } | awk '
{	if(empty)
		print "\r"
	if($0 != "\r") {
		print
		empty = 0
	} else	empty = 1
}' > "${2:-newfile}"

If you want to try this on a Solaris/SunOS system, change awk to /usr/xpg4/bin/awk or nawk .

This script takes two operands. The first operand is the name of the input file you want to process. The second operand is the name of the output file you want to produce. If neither of these operands are specified on the command line, the input file name defaults to file and the output file name defaults to newfile .

Assuming you are using Unix/Linux and are only interested in appending a line terminator to the last line if it doesn't already exist, you could use ed :

$ echo wq | ed myfile
Newline appended
18
18
 $

Andrew

Hi Don, I see where you are going, I may have read the question wrong, I interpreted it as "add a carriage return is it is missing at the end of a line (which ends in linefeed)". So for that, my suggestion does not use extensions - GNU or otherwise - to the standard. I did not mean to also correct a missing newline at the end of the file.

It may be good to note that even though the latter case is not defined by the standards, every implementation of awk on every OS I know does read the unterminated last line and adds the newline at the end of the file, so IMO this behavior cannot be labeled as a GNU extension.

Like awk and sed , ed has unspecified behavior if the file you are editing is not a text file. The code above may work on some systems, but it is not portable and will not work on all UNIX/Linux/BSD systems!

However, if you change ed to ex , the above code should work portably.

1 Like

Hi Scrutinizer,
Note that the title of this thread (and the description in post #1 in this thread) says "add Carriage Return and Line Feed"; not "add Carriage Return before Line Feed". The description to me sounded like the input file is a DOS text file with <carriage-return><line-feed>(AKA <newline>) line separators that the submitter wants to turn into a DOS text file with complete DOS lines including a <carriage-return><line-feed> terminator at the end of the last line.

The standards say that the behavior is only defined for awk if all input files are text files. It doesn't make any exception to that requirement for files that are text files except for a partial final line. (The standards do make that exception for the ex utility.)

I am almost positive that PWB UNIX, UNIX System III, UNIX System V, and the Solaris /usr/xpg4/bin versions of awk (at least through early Solaris 10 updates) dropped partial lines without feeding them (with or without an added <newline>) through the script. But, I don't have access to any of those systems to verify it as this point. BSD/macOS awk does add a <newline> terminator to a partial line at the end of a file so it is an extension that is provided by GNU and other systems.

I have been on this forum long enough that I do not expect exact specifications in the title. I interpreted this to mean a CRLF line ending instead of a LF ending. Do nothing when there is CRLF and change when only LF. It did not make sense to me otherwise.

I know, I already said that I did not try to correct a failing newline at the end of the file with my suggestion. That is not how I interpreted it, I may be wrong..

I don't know about really ancient versions, but I just tested with oawk, nawk, and /usr/xpg4/bin/awk on Solaris 10u11, awk on HPUX and AIX and Tru64. All read the unterminated last line and add a newline.. It may be that on older versions of Solaris it did not do that, but I think the awk utility has not changed in this respect (why would they put effort in "fixing" oawk or nawk if they are only there for legacy reasons?).

Hi Don,

One small change , what if I only need to add the LF if it does not exist at the end of the file , do I just remove the \r from the code ?

Please advise

I think you mean the post#8 script.
Yes, delete all \r so you get '\n' and two times ""

Now echo and sed (where one had a problem to specify a \r in a portable way) can be used:

#!/bin/sh
{ cat "${1:-file}"; echo; } | sed '
  $!b
  /^$/d
' > "${2:-newfile}"

Is this correct

{ cat "${1:-file}"; printf '\n'; } | awk '
{	if(empty)
		print "\n"
	if($0 != "\n") {
		print
		empty = 0
	} else	empty = 1
}' > "${2:-newfile}"

No. MadeInGermany's suggestion to delete all \r so you get '\n' and two times "" meant exactly what he said... Delete ALL \r means delete all \r ; not delete the first \r and change the other two to \n !

{ cat "${1:-file}"; printf '\n'; } | awk '
{	if(empty)
		print ""
	if($0 != "") {
		print
		empty = 0
	} else	empty = 1
}' > "${2:-newfile}"

Note also that printf '\n'; can be simplified to just be echo; and still get the same results.

But, using the suggestion proposed by apmcd47 would be more efficient:

printf 'w %s\nq\n' "${2:-newfile}" | ex "${1:-file}"

since we're now creating a UNIX text file instead of a DOS text file.