11#! /usr/bin/env bash
22# Nerd Fonts Version: 3.4.0
3- # Script Version: 1.4.5
3+ # Script Version: 1.4.6
44#
55# You can supply options to the font-patcher via environment variable NERDFONTS
66# That option will override the defaults (also defaults of THIS script).
@@ -142,24 +142,64 @@ then
142142 exit 1
143143fi
144144
145+ # Build find command with optional filter
146+ # Construct find command by placing parentheses directly in the find call rather than in the array
147+ # This ensures parentheses are correctly interpreted by find as grouping operators
145148if [ $# -eq 1 ]
146149then
147- if [[ " ${1: 0: 1} " == " /" ]]
150+ filter_arg=" $1 "
151+ if [[ " ${filter_arg: 0: 1} " == " /" ]]
148152 then
149- like_pattern=" .*$1 /.*\.\(otf\|ttf\|sfd\)"
150- echo " $LINE_PREFIX Filter given, limiting search and patch to pathname pattern '$1 '"
153+ # Directory filter: match fonts in directories containing the filter
154+ filter_dir=" ${filter_arg#/ } " # Remove leading /
155+ # For directory filter, -ipath must be outside the parentheses grouping
156+ find_cmd_args=(-iname " *.ttf" -o -iname " *.otf" -o -iname " *.sfd" )
157+ find_path_filter=" -ipath"
158+ find_path_pattern=" *${filter_dir} /*"
159+ find_path_filter_with_pattern=(-ipath " *${filter_dir} /*" )
160+ echo " $LINE_PREFIX Filter given, limiting search and patch to pathname pattern '$filter_arg '"
161+ # Pattern for directory filter: match paths containing the directory
162+ like_pattern=" .*/${filter_dir} /.*\.\(otf\|ttf\|sfd\)"
151163 else
152- like_pattern=" .*/$1 [^/]*\.\(otf\|ttf\|sfd\)"
153- echo " $LINE_PREFIX Filter given, limiting search and patch to filename pattern '$1 '"
164+ # Filename filter: match fonts with filter in filename
165+ find_cmd_args=(-iname " *${filter_arg} *.ttf" -o -iname " *${filter_arg} *.otf" -o -iname " *${filter_arg} *.sfd" )
166+ find_path_filter=" "
167+ find_path_pattern=" "
168+ find_path_filter_with_pattern=()
169+ echo " $LINE_PREFIX Filter given, limiting search and patch to filename pattern '$filter_arg '"
170+ # Pattern for filename filter: match filter in filename
171+ like_pattern=" .*${filter_arg} .*\.\(otf\|ttf\|sfd\)"
154172 fi
173+ else
174+ # No filter
175+ find_cmd_args=(-iname " *.ttf" -o -iname " *.otf" -o -iname " *.sfd" )
176+ find_path_filter=" "
177+ find_path_pattern=" "
178+ find_path_filter_with_pattern=()
179+ like_pattern=' .*\.\(otf\|ttf\|sfd\)'
155180fi
156181
157182# correct way to output find results into an array (when files have space chars, etc)
158183# source: https://stackoverflow.com/questions/8213328/bash-script-find-output-to-array
184+ # Use -iname instead of -iregex for better macOS compatibility
185+ # Place parentheses directly in the find command to ensure they're interpreted as grouping operators
186+ # This avoids issues with parentheses in arrays by constructing the find command explicitly
159187source_fonts=()
160- while IFS= read -d $' \0' -r file ; do
161- source_fonts=(" ${source_fonts[@]} " " $file " )
162- done < <( find " $source_fonts_dir " -iregex " ${like_pattern} " -type f -print0)
188+ if [ -n " $find_path_filter " ]; then
189+ # Directory filter: -ipath must be outside the parentheses grouping
190+ # -type f must be outside parentheses to apply to all conditions
191+ # Disable glob expansion to prevent shell from expanding wildcard patterns in find_cmd_args
192+ while IFS= read -d $' \0' -r file ; do
193+ source_fonts=(" ${source_fonts[@]} " " $file " )
194+ done < <( set -f; find " $source_fonts_dir " " ${find_path_filter_with_pattern[@]} " " (" " ${find_cmd_args[@]} " " )" -type f -print0)
195+ else
196+ # Filename filter or no filter: group conditions with parentheses
197+ # -type f must be outside parentheses to apply to all -iname conditions
198+ # Disable glob expansion to prevent shell from expanding wildcard patterns in find_cmd_args
199+ while IFS= read -d $' \0' -r file ; do
200+ source_fonts=(" ${source_fonts[@]} " " $file " )
201+ done < <( set -f; find " $source_fonts_dir " " (" " ${find_cmd_args[@]} " " )" -type f -print0)
202+ fi
163203
164204# print total number of source fonts found
165205echo " $LINE_PREFIX Total source fonts found: ${# source_fonts[*]} "
@@ -169,10 +209,17 @@ if [ -z "${SOURCE_DATE_EPOCH}" ]
169209then
170210 export SOURCE_DATE_EPOCH=$( date +%s)
171211fi
172- release_timestamp=$( date -R " --date=@${SOURCE_DATE_EPOCH} " 2> /dev/null) || {
212+ # Detect GNU vs BSD date implementations reliably
213+ if date -R " --date=@${SOURCE_DATE_EPOCH} " > /dev/null 2>&1 ; then
214+ # GNU date (Linux and others)
215+ release_timestamp=$( date -R " --date=@${SOURCE_DATE_EPOCH} " 2> /dev/null)
216+ elif date -r " ${SOURCE_DATE_EPOCH} " " +%a, %d %b %Y %H:%M:%S %z" > /dev/null 2>&1 ; then
217+ # BSD date (macOS) - uses -r with epoch seconds
218+ release_timestamp=$( date -r " ${SOURCE_DATE_EPOCH} " " +%a, %d %b %Y %H:%M:%S %z" )
219+ else
173220 echo >&2 " $LINE_PREFIX Invalid release timestamp SOURCE_DATE_EPOCH: ${SOURCE_DATE_EPOCH} "
174221 exit 2
175- }
222+ fi
176223echo " $LINE_PREFIX Release timestamp is ${release_timestamp} "
177224
178225function patch_font {
@@ -192,7 +239,24 @@ function patch_font {
192239 orig_font_date=$( ttfdump -t head " ${one_font} " | \
193240 grep -E ' [^a-z]modified:.*0x' | sed ' s/.*x//' | tr ' a-f' ' A-F' )
194241 SOURCE_DATE_EPOCH=$( dc -e " 16i ${orig_font_date} Ai 86400 24107 * - p" )
195- echo " $LINE_PREFIX Release timestamp adjusted to $( date -R " --date=@${SOURCE_DATE_EPOCH} " ) "
242+ # Adjust timestamp using the same GNU/BSD date detection logic
243+ if date --version > /dev/null 2>&1 ; then
244+ # GNU date
245+ adjusted_timestamp=$( date -R " --date=@${SOURCE_DATE_EPOCH} " 2> /dev/null) || {
246+ echo >&2 " $LINE_PREFIX Invalid adjusted timestamp SOURCE_DATE_EPOCH calculated from font metadata: ${SOURCE_DATE_EPOCH} "
247+ exit 2
248+ }
249+ elif date -r " ${SOURCE_DATE_EPOCH} " " +%a, %d %b %Y %H:%M:%S %z" > /dev/null 2>&1 ; then
250+ # BSD date
251+ adjusted_timestamp=$( date -r " ${SOURCE_DATE_EPOCH} " " +%a, %d %b %Y %H:%M:%S %z" ) || {
252+ echo >&2 " $LINE_PREFIX Invalid adjusted timestamp SOURCE_DATE_EPOCH calculated from font metadata: ${SOURCE_DATE_EPOCH} "
253+ exit 2
254+ }
255+ else
256+ echo >&2 " $LINE_PREFIX Unable to convert adjusted timestamp SOURCE_DATE_EPOCH: ${SOURCE_DATE_EPOCH} (no compatible date command found)"
257+ exit 2
258+ fi
259+ echo " $LINE_PREFIX Release timestamp adjusted to ${adjusted_timestamp} "
196260 fi
197261 fi
198262
@@ -341,8 +405,32 @@ then
341405 # to follow font naming changed. We can not do this if we patch only
342406 # some of the source font files in that directory.
343407 last_source_dir=${current_source_dir}
344- num_to_patch=$( find " ${current_source_dir} " -iregex " ${like_pattern} " -type f | wc -l)
345- num_existing=$( find " ${current_source_dir} " -iname " *.[ot]tf" -o -iname " *.sfd" -type f | wc -l)
408+ # Count fonts matching the filter criteria in this directory
409+ if [ -n " ${filter_arg:- } " ]
410+ then
411+ if [[ " ${filter_arg: 0: 1} " == " /" ]]
412+ then
413+ # Directory filter: count fonts matching the -ipath pattern "*${filter_dir}/*"
414+ # Verify that fonts are in the current directory AND match the filter_dir pattern
415+ filter_dir=" ${filter_arg#/ } " # Remove leading /
416+ num_to_patch=0
417+ for font_path in " ${source_fonts[@]} " ; do
418+ # Check that font is in current directory AND path contains the filter_dir pattern
419+ if [[ " $( dirname " $font_path " ) " == " $current_source_dir " ]] && \
420+ [[ " $font_path " == * " ${filter_dir} " * ]]; then
421+ (( num_to_patch++ ))
422+ fi
423+ done
424+ else
425+ # Filename filter: count fonts that start with the filter
426+ num_to_patch=$( find " ${current_source_dir} " " (" -iname " ${filter_arg} *.ttf" -o -iname " ${filter_arg} *.otf" -o -iname " ${filter_arg} *.sfd" " )" -type f | wc -l)
427+ fi
428+ else
429+ # No filter: count all fonts in directory
430+ num_to_patch=$( find " ${current_source_dir} " " (" -iname " *.ttf" -o -iname " *.otf" -o -iname " *.sfd" " )" -type f | wc -l)
431+ fi
432+ # Always count all fonts in directory for comparison
433+ num_existing=$( find " ${current_source_dir} " " (" -iname " *.ttf" -o -iname " *.otf" -o -iname " *.sfd" " )" -type f | wc -l)
346434 if [ " ${num_to_patch} " -eq " ${num_existing} " ]
347435 then
348436 purge_destination=" TRUE"
0 commit comments