Issue
I've a lot of PHP files and I'd like to fix newline character after the last line (if not present) with a bash script.
Is there any command to to that easily?
Thanks :)
Solution
Short and quick tee
But adding a newline at end of each files. For strictly adding a newline at end of files where there are not, please go to second part of this answer!
tee
is the tool you're searching for:
Simply:
tee -a <<<'' file1 file2 ...
or
find /path -type f ! -empty -name '*.php' -exec tee -a <<<'' {} +
Warning: Don't miss -a
option!
It's very quick, but add a newline on each files.
(You could whipe in a second command like sed '${/^$/d}' -i file1 file2 ...
all empty last lines in all files. ;)
(Warning again: I insist: if you miss -a
flag for tee
command, this will shortly and quickly replace the content of each file found by a newline!! So all your files will become empty!)
Some explanation:
from man tee
:
NAME tee - read from standard input and write to standard output and files SYNOPSIS tee [OPTION]... [FILE]... DESCRIPTION Copy standard input to each FILE, and also to standard output. -a, --append append to the given FILEs, do not overwrite
- So
tee
will reproduce, appending (because of optiona
), to each file submited as argument, what become on standard input. - bash feature: "
here strings
" (seeman -Pless\ +/Here.Strings bash
), you could usecommand <<<"here string""
in replacement ofecho "here string"| command
. For this, bash add a newline to submited string (even empty string:<<<''
).
Slower, but stronger
fix newline character after the last line (if not present)
Stay very quick because of limited forks, but one fork to tail -c1
have to be done for each files anyway!
while IFS= read -d '' -r file
do
IFS= read -d "" chr < <(
exec tail -c1 "$file"
)
if [[ $chr != $'\n' ]]
then
echo >> "$file"
fi
done < <(
find . -type f ! -empty -name '*.php' -print0
)
Could by written more compact:
while IFS= read -d '' -r file; do
IFS= read -d "" chr < <( exec tail -c1 "$file" )
[[ $chr != $'\n' ]] && echo >> "$file"
done < <( find . -type f ! -empty -name '*.php' -print0 )
find -print0
print each filename separated by a null character\0
.IFS= read -d '' -r file
don't consider special characters nor spaces, so$file
could hold any kind of filename, event containing spaces or accented characters.exec
tell bash to executetail
as subprocess, avoid default second fork runningtail
in asubsubprocess
.tail -c1
read last caracter of$file
IFS= read -d "" chr
store last caracter into$chr
variable.
Answered By - F. Hauri - Give Up GitHub Answer Checked By - Cary Denson (WPSolving Admin)