Skip to content

Commit cf7efef

Browse files
authored
Update last_line_empty.sh
1 parent e6277cd commit cf7efef

File tree

1 file changed

+86
-80
lines changed

1 file changed

+86
-80
lines changed

src/last_line_empty.sh

+86-80
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,134 @@
11
#!/usr/bin/env bash
22
#
33
# Script Name: assert_last_line_empty.sh
4-
# Description: Ensures that files end with exactly one trailing empty line.
5-
# “Empty” here means a line that is either completely empty
6-
# or contains only whitespace. In particular, if there are multiple
7-
# trailing empty lines (or lines with only spaces/tabs), they will be
8-
# squashed to a single trailing empty line.
4+
# Description: Ensures that text files end with exactly one trailing newline,
5+
# collapsing multiple trailing empty lines (containing only
6+
# whitespace/tabs/newlines) down to a single newline. Files
7+
# that are empty (0 bytes) are unchanged; files containing only
8+
# whitespace become a single blank line; binary files are skipped.
99
#
10-
# Usage: assert_last_line_empty.sh [--check] <file_or_directory_path>
10+
# Usage: assert_last_line_empty.sh [--check] <file_or_directory_path>
11+
# --check : Only check and report problems; do not change files.
12+
# <file_or_directory_path> : A file or directory to process.
1113
#
12-
# --check : Only check and report problems; do not change files.
13-
# <file_or_directory_path> : a file or directory to process.
14-
#
15-
# Example: ./assert_last_line_empty.sh --check path/to/file.txt
14+
# Example: ./assert_last_line_empty.sh --check path/to/file.txt
1615
#
1716

18-
checkonly=0 # Flag indicating if we're only checking (no fixes)
19-
status=0 # Global exit status to track if any file needs fixing
17+
checkonly=0 # Flag to indicate we only check (no fixes)
18+
status=0 # Will become 1 if any file needs changes in --check mode
2019

2120
###############################################################################
22-
# normalize_file_content: outputs the normalized content for a file:
23-
# 1. If the file is empty (0 bytes), we output it as-is (no changes).
24-
# 2. If the file is non-empty but contains only whitespace/newlines,
25-
# we normalize it to exactly one empty line.
26-
# 3. Otherwise, we remove trailing whitespace on every line, remove all
27-
# trailing blank lines, and then add exactly one trailing newline.
21+
# normalize_file_content
22+
# - If empty file (0 bytes), output as is (no change).
23+
# - If file contains only whitespace, collapse to a single newline.
24+
# - Otherwise (it has non-whitespace):
25+
# * Remove trailing spaces/tabs on each line.
26+
# * If file has no newline at all, add exactly one.
27+
# * If file has at least one newline, remove any extra trailing
28+
# blank lines (including whitespace-only lines) so that we
29+
# end with exactly one newline.
2830
###############################################################################
2931
normalize_file_content() {
3032
local file="$1"
3133

32-
# If the file is empty (0 bytes), do nothing:
34+
# 1) If empty, do nothing:
3335
if [ ! -s "$file" ]; then
34-
cat "$file"
36+
cat "$file" # or just 'return' if you prefer truly empty
3537
return
3638
fi
3739

38-
# Check if the file has any non-whitespace character:
40+
# 2) If file is all whitespace (spaces/tabs/newlines):
3941
if ! grep -q '[^[:space:]]' "$file" 2>/dev/null; then
40-
# The file contains only whitespace / newlines => normalize to one empty line
42+
# Collapse it to a single newline:
4143
printf "\n"
42-
else
43-
# 1) Remove trailing spaces/tabs from each line
44-
# 2) Remove all trailing blank lines
45-
# 3) Add exactly one newline at the end
46-
sed 's/[ \t]*$//' "$file" \
47-
| sed -e ':a' -e '/^$/{$d;N;ba}' \
48-
; printf "\n"
44+
return
4945
fi
46+
47+
# 3) If the file has no newline at all:
48+
if ! grep -q $'\n' "$file"; then
49+
# Remove trailing spaces/tabs, then add exactly one newline:
50+
sed 's/[ \t]*$//' "$file"
51+
printf "\n"
52+
return
53+
fi
54+
55+
# 4) File has non-whitespace *and* at least one newline:
56+
# - Remove trailing spaces/tabs from each line
57+
# - Remove all trailing empty lines
58+
# - End with exactly one newline
59+
sed 's/[ \t]*$//' "$file" \
60+
| sed -e ':a' -e '/^[[:space:]]*$/N; /^\n*$/ba'
61+
printf "\n"
5062
}
5163

5264
###############################################################################
53-
# assert_last_line_empty: Checks (and optionally fixes) a single file.
65+
# assert_last_line_empty
66+
# - Checks (and optionally fixes) a single file.
67+
# - Skips binary files (by checking if grep thinks it is binary).
68+
# - Logs changes.
5469
###############################################################################
5570
assert_last_line_empty() {
5671
local file="$1"
57-
echo "Processing file: ${file}"
72+
echo "Processing file: $file"
5873

59-
if [ ! -f "${file}" ]; then
60-
echo "Error: ${file} is not a regular file."
74+
# Skip if not a regular file:
75+
if [ ! -f "$file" ]; then
76+
echo " [ERROR] Not a regular file: $file"
6177
return 1
6278
fi
6379

64-
# Create a temporary normalized version of the file
65-
local norm
66-
norm="$(mktemp)"
80+
# Skip if binary:
81+
if ! grep -Iq . "$file"; then
82+
echo " [SKIP] Binary file (not modified): $file"
83+
return 0
84+
fi
6785

68-
normalize_file_content "${file}" > "${norm}"
86+
# Create temporary normalized version of the file
87+
local tmp norm
88+
tmp="$(mktemp -t assert_last_line_empty.XXXXXX)"
6989

70-
if [ $checkonly -eq 1 ]; then
71-
# Compare the normalized file with the original
72-
if diff -q "${file}" "${norm}" >/dev/null; then
73-
echo "Already normalized: ${file}"
74-
else
75-
echo "Normalization required: ${file}"
76-
status=1
77-
fi
78-
rm -f "${norm}"
90+
normalize_file_content "$file" > "$tmp"
91+
92+
# Compare to see if changes needed:
93+
if diff -q "$file" "$tmp" >/dev/null; then
94+
echo " [OK] No changes needed: $file"
95+
rm -f "$tmp"
7996
else
80-
# In fix mode, overwrite the file only if there is a change
81-
if diff -q "${file}" "${norm}" >/dev/null; then
82-
echo "No changes needed: ${file}"
83-
rm -f "${norm}"
97+
if [ "$checkonly" -eq 1 ]; then
98+
echo " [CHECK] Normalization required: $file"
99+
status=1
100+
rm -f "$tmp"
84101
else
85-
mv "${norm}" "${file}"
86-
echo "File fixed: ${file}"
102+
mv "$tmp" "$file"
103+
echo " [FIXED] File updated: $file"
87104
fi
88105
fi
89106
}
90107

91108
###############################################################################
92-
# process_file: Wrapper to normalize a single file.
93-
###############################################################################
94-
process_file() {
95-
local file="$1"
96-
assert_last_line_empty "${file}"
97-
}
98-
99-
###############################################################################
100-
# process_directory: Recursively process all files in a directory.
109+
# process_directory
110+
# - Recursively process all regular files in a directory.
101111
###############################################################################
102112
process_directory() {
103113
local directory="$1"
104114

105-
if [ ! -d "${directory}" ]; then
106-
echo "Error: ${directory} is not a directory."
115+
if [ ! -d "$directory" ]; then
116+
echo "Error: $directory is not a directory."
107117
return 1
108118
fi
109119

110-
echo "Processing directory: ${directory}"
111-
# Use find to locate all regular files
112-
while IFS= read -r -d '' file; do
113-
process_file "${file}"
114-
done < <(find "${directory}" -type f -print0)
120+
echo "Recursively processing directory: $directory"
121+
find "$directory" -type f -print0 2>/dev/null \
122+
| while IFS= read -r -d '' file; do
123+
assert_last_line_empty "$file"
124+
done
115125
}
116126

117127
###############################################################################
118-
# main: Script entry point
128+
# main: entry point
119129
###############################################################################
120130
main() {
121131
if [ $# -eq 0 ]; then
122-
echo "Error: No path provided."
123132
echo "Usage: $0 [--check] <file_or_directory_path>"
124133
exit 1
125134
fi
@@ -130,20 +139,17 @@ main() {
130139
fi
131140

132141
local path="$1"
133-
134-
if [ -d "${path}" ]; then
135-
process_directory "${path}"
136-
elif [ -f "${path}" ]; then
137-
process_file "${path}"
142+
if [ -d "$path" ]; then
143+
process_directory "$path"
144+
elif [ -f "$path" ]; then
145+
assert_last_line_empty "$path"
138146
else
139-
echo "Error: ${path} is not a valid file or directory."
147+
echo "Error: $path is not a valid file or directory."
140148
exit 1
141149
fi
142150

143-
# If any file required normalization in --check mode, exit non-zero
144-
if [ $status -ne 0 ]; then
145-
exit 1
146-
fi
151+
# If in --check mode, and we found at least one file needing changes, exit 1
152+
exit "$status"
147153
}
148154

149155
main "$@"

0 commit comments

Comments
 (0)