[tz] [PROPOSED 05/12] Assume POSIX.2 command substitution

Paul Eggert eggert at cs.ucla.edu
Sat Jun 1 18:33:50 UTC 2024


* tzselect.ksh: Use $(...) instead of `...`.
---
 NEWS         |  4 +++
 tzselect.ksh | 82 ++++++++++++++++++++++++----------------------------
 2 files changed, 42 insertions(+), 44 deletions(-)

diff --git a/NEWS b/NEWS
index 1771c8dd..92984445 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,7 @@ Unreleased, experimental changes
     The main data form now uses %z.
     The code now conforms to RFC 8536 for early timestamps.
     Support POSIX.1-2024, which removes asctime_r and ctime_r.
+    Assume POSIX.2-1992 or later for shell scripts.
     Improve historical data for Portugal and possessions.
 
   Changes to data
@@ -59,6 +60,9 @@ Unreleased, experimental changes
     can overrun user buffers.  If you still need them, add
     -DSUPPORT_POSIX2008 to CFLAGS.
 
+    tzselect now assumes POSIX.2-1992 or later, as practical porting
+    targets now all support this.
+
   Changes to build procedure
 
     'make check' no longer requires curl and Internet access.
diff --git a/tzselect.ksh b/tzselect.ksh
index 38941bbc..8a80cd67 100644
--- a/tzselect.ksh
+++ b/tzselect.ksh
@@ -20,12 +20,6 @@ REPORT_BUGS_TO=tz at iana.org
 #	Korn Shell <http://www.kornshell.com/>
 #	MirBSD Korn Shell <http://www.mirbsd.org/mksh.htm>
 #
-# For portability to Solaris 10 /bin/sh (supported by Oracle through
-# January 2027) this script avoids some POSIX features and common
-# extensions, such as $(...), $((...)), ! CMD, unquoted ^, ${#ID},
-# ${ID##PAT}, ${ID%%PAT}, and $10.  Although some of these constructs
-# work sometimes, it's simpler to avoid them entirely.
-#
 # This script also uses several features of POSIX awk.
 # If your host lacks awk, or has an old awk that does not conform to POSIX,
 # you can use any of the following free programs instead:
@@ -45,7 +39,7 @@ set -f
 
 # Specify default values for environment variables if they are unset.
 : ${AWK=awk}
-: ${PWD=`pwd`}
+: ${PWD=$(pwd)}
 : ${TZDIR=$PWD}
 
 # Output one argument as-is to standard output, with trailing newline.
@@ -118,7 +112,7 @@ else
   doselect() {
     # Field width of the prompt numbers.
     print_nargs_length="BEGIN {print length(\"$#\");}"
-    select_width=`$AWK "$print_nargs_length"`
+    select_width=$($AWK "$print_nargs_length")
 
     select_i=
 
@@ -129,14 +123,14 @@ else
 	select_i=0
 	for select_word
 	do
-	  select_i=`$AWK "BEGIN { print $select_i + 1 }"`
+	  select_i=$($AWK "BEGIN { print $select_i + 1 }")
 	  printf >&2 "%${select_width}d) %s\\n" $select_i "$select_word"
 	done;;
       *[!0-9]*)
 	echo >&2 'Please enter a number in range.';;
       *)
 	if test 1 -le $select_i && test $select_i -le $#; then
-	  shift `$AWK "BEGIN { print $select_i - 1 }"`
+	  shift $($AWK "BEGIN { print $select_i - 1 }")
 	  select_result=$1
 	  break
 	fi
@@ -170,7 +164,7 @@ do
   esac
 done
 
-shift `$AWK "BEGIN { print $OPTIND - 1 }"`
+shift $($AWK "BEGIN { print $OPTIND - 1 }")
 case $# in
 0) ;;
 *) say >&2 "$0: $1: unknown argument"; exit 1
@@ -192,10 +186,10 @@ fi
 # if that does not work, fall back on 'cat'.
 read_file() {
   { $translit && {
-    eval "$1=\`(iconv -f UTF-8 -t //TRANSLIT) 2>/dev/null <\"\$2\"\`" ||
-    eval "$1=\`(iconv -f UTF-8) 2>/dev/null <\"\$2\"\`"
+    eval "$1=\$( (iconv -f UTF-8 -t //TRANSLIT) 2>/dev/null <\"\$2\")" ||
+    eval "$1=\$( (iconv -f UTF-8) 2>/dev/null <\"\$2\")"
   }; } ||
-  eval "$1=\`cat <\"\$2\"\`" || {
+  eval "$1=\$(cat <\"\$2\")" || {
     say >&2 "$0: time zone files are not set up correctly"
     exit 1
   }
@@ -403,7 +397,7 @@ while
     echo >&2 \
       'Please select a continent, ocean, "coord", "TZ", "time", or "now".'
 
-    quoted_continents=`
+    quoted_continents=$(
       $AWK '
 	function handle_entry(entry) {
 	  entry = substr(entry, 1, index(entry, "/") - 1)
@@ -433,7 +427,7 @@ while
       sort -u |
       tr '\n' ' '
       echo ''
-    `
+    )
 
     eval '
       doselect '"$quoted_continents"' \
@@ -507,14 +501,14 @@ while
 	  '74 degrees 3 minutes west.'
 	read coord
       esac
-      distance_table=`
+      distance_table=$(
 	$AWK \
 	  "$output_distances_or_times" \
 	  ="$coord" ="$TZ_COUNTRY_TABLE" ="$TZ_ZONE_TABLE" |
 	sort -n |
 	$AWK "{print} NR == $location_limit { exit }"
-      `
-      regions=`
+      )
+      regions=$(
 	$AWK '
 	  BEGIN {
 	    distance_table = substr(ARGV[1], 2)
@@ -526,13 +520,13 @@ while
 	    }
 	  }
 	' ="$distance_table"
-      `
+      )
       echo >&2 'Please select one of the following timezones,'
       echo >&2 'listed roughly in increasing order' \
 	"of distance from $coord".
       doselect $regions
       region=$select_result
-      tz=`
+      tz=$(
 	$AWK '
 	  BEGIN {
 	    distance_table = substr(ARGV[1], 2)
@@ -546,22 +540,22 @@ while
 	    }
 	  }
 	' ="$distance_table" ="$region"
-      `;;
+      );;
     *)
       case $continent in
       now|time)
 	minute_format='%a %b %d %H:%M'
-	old_minute=`TZ=UTC0 date +"$minute_format"`
+	old_minute=$(TZ=UTC0 date +"$minute_format")
 	for i in 1 2 3
 	do
-	  time_table_command=`
+	  time_table_command=$(
 	    $AWK \
 	      -v output_times=1 \
 	      "$output_distances_or_times" \
 	      = = ="$TZ_ZONE_TABLE"
-	  `
-	  time_table=`eval "$time_table_command"`
-	  new_minute=`TZ=UTC0 date +"$minute_format"`
+	  )
+	  time_table=$(eval "$time_table_command")
+	  new_minute=$(TZ=UTC0 date +"$minute_format")
 	  case $old_minute in
 	  "$new_minute") break
 	  esac
@@ -569,11 +563,11 @@ while
 	done
 	echo >&2 "The system says Universal Time is $new_minute."
 	echo >&2 "Assuming that's correct, what is the local time?"
-	sorted_table=`say "$time_table" | sort -k2n -k2,5 -k1n` || {
+	sorted_table=$(say "$time_table" | sort -k2n -k2,5 -k1n) || {
 	  say >&2 "$0: cannot sort time table"
 	  exit 1
 	}
-	eval doselect `
+	eval doselect $(
 	  $AWK '
 	    BEGIN {
 	      sorted_table = substr(ARGV[1], 2)
@@ -590,10 +584,10 @@ while
 	      }
 	    }
 	  ' ="$sorted_table"
-	`
+	)
 	time=$select_result
 	continent_re='^'
-	zone_table=`
+	zone_table=$(
 	  $AWK '
 	    BEGIN {
 	      time = substr(ARGV[1], 2)
@@ -609,13 +603,13 @@ while
 	      }
 	    }
 	  ' ="$time" ="$time_table"
-	`
-	countries=`
+	)
+	countries=$(
 	  $AWK \
 	    "$output_country_list" \
 	    ="$continent_re" ="$TZ_COUNTRY_TABLE" ="$zone_table" |
 	  sort -f
-	`
+	)
 	;;
       *)
 	continent_re="^$continent/"
@@ -623,16 +617,16 @@ while
       esac
 
       # Get list of names of countries in the continent or ocean.
-      countries=`
+      countries=$(
 	$AWK \
 	  "$output_country_list" \
 	  ="$continent_re" ="$TZ_COUNTRY_TABLE" ="$zone_table" |
 	sort -f
-      `
+      )
       # If all zone table entries have comments, and there are
       # at most 22 entries, asked based on those comments.
       # This fits the prompt onto old-fashioned 24-line screens.
-      regions=`
+      regions=$(
 	$AWK '
 	  BEGIN {
 	    TZ_ZONE_TABLE = substr(ARGV[1], 2)
@@ -653,7 +647,7 @@ while
 		print comment[i]
 	  }
 	' ="$zone_table"
-      `
+      )
 
       # If there's more than one country, ask the user which one.
       case $countries in
@@ -669,7 +663,7 @@ while
 
 
       # Get list of timezones in the country.
-      regions=`
+      regions=$(
 	$AWK '
 	  BEGIN {
 	    country = substr(ARGV[1], 2)
@@ -696,7 +690,7 @@ while
 	    }
 	  }
 	' ="$country" ="$TZ_COUNTRY_TABLE" ="$zone_table"
-      `
+      )
 
       # If there's more than one region, ask the user which one.
       case $regions in
@@ -707,7 +701,7 @@ while
       esac
 
       # Determine tz from country and region.
-      tz=`
+      tz=$(
 	$AWK '
 	  BEGIN {
 	    country = substr(ARGV[1], 2)
@@ -735,7 +729,7 @@ while
 	    }
 	  }
 	' ="$country" ="$region" ="$TZ_COUNTRY_TABLE" ="$zone_table"
-      `
+      )
     esac
 
     # Make sure the corresponding zoneinfo file exists.
@@ -754,8 +748,8 @@ while
   extra_info=
   for i in 1 2 3 4 5 6 7 8
   do
-    TZdate=`LANG=C TZ="$TZ_for_date" date`
-    UTdate=`LANG=C TZ=UTC0 date`
+    TZdate=$(LANG=C TZ="$TZ_for_date" date)
+    UTdate=$(LANG=C TZ=UTC0 date)
     if $AWK '
 	  function getsecs(d) {
 	    return match(d, /.*:[0-5][0-9]/) ? substr(d, RLENGTH - 1, 2) : ""
-- 
2.45.1



More information about the tz mailing list