mirror of https://github.com/tLDP/LDP
new
This commit is contained in:
parent
36ecdef705
commit
02ca4d5e31
|
@ -0,0 +1,28 @@
|
|||
#!/bin/bash
|
||||
# Du.sh: DOS to UNIX text file converter.
|
||||
|
||||
E_WRONGARGS=65
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Usage: `basename $0` filename-to-convert"
|
||||
exit $E_WRONGARGS
|
||||
fi
|
||||
|
||||
NEWFILENAME=$1.unx
|
||||
|
||||
CR='\015' # Carriage return.
|
||||
# 015 is octal ASCII code for CR.
|
||||
# Lines in a DOS text file end in a CR-LF.
|
||||
|
||||
tr -d $CR < $1 > $NEWFILENAME
|
||||
# Delete CR's and write to new file.
|
||||
|
||||
echo "Original DOS text file is \"$1\"."
|
||||
echo "Converted UNIX text file is \"$NEWFILENAME\"."
|
||||
|
||||
exit 0
|
||||
|
||||
# Exercise:
|
||||
# --------
|
||||
# Change the above script to convert from UNIX to DOS.
|
|
@ -0,0 +1,111 @@
|
|||
#! /bin/bash
|
||||
# array-append.bash
|
||||
|
||||
# Copyright (c) Michael S. Zick, 2003, All rights reserved.
|
||||
# License: Unrestricted reuse in any form, for any purpose.
|
||||
# Version: $ID$
|
||||
#
|
||||
# Slightly modified in formatting by M.C.
|
||||
|
||||
|
||||
# Array operations are Bash-specific.
|
||||
# Legacy UNIX /bin/sh lacks equivalents.
|
||||
|
||||
|
||||
# Pipe the output of this script to 'more'
|
||||
#+ so it doesn't scroll off the terminal.
|
||||
|
||||
|
||||
# Subscript packed.
|
||||
declare -a array1=( zero1 one1 two1 )
|
||||
# Subscript sparse ([1] is not defined).
|
||||
declare -a array2=( [0]=zero2 [2]=two2 [3]=three2 )
|
||||
|
||||
echo
|
||||
echo '- Confirm that the array is really subscript sparse. -'
|
||||
echo "Number of elements: 4" # Hard-coded for illustration.
|
||||
for (( i = 0 ; i < 4 ; i++ ))
|
||||
do
|
||||
echo "Element [$i]: ${array2[$i]}"
|
||||
done
|
||||
# See also the more general code example in basics-reviewed.bash.
|
||||
|
||||
|
||||
declare -a dest
|
||||
|
||||
# Combine (append) two arrays into a third array.
|
||||
echo
|
||||
echo 'Conditions: Unquoted, default IFS, All-Elements-Of operator'
|
||||
echo '- Undefined elements not present, subscripts not maintained. -'
|
||||
# # The undefined elements do not exist; they are not being dropped.
|
||||
|
||||
dest=( ${array1[@]} ${array2[@]} )
|
||||
# dest=${array1[@]}${array2[@]} # Strange results, possibly a bug.
|
||||
|
||||
# Now, list the result.
|
||||
echo
|
||||
echo '- - Testing Array Append - -'
|
||||
cnt=${#dest[@]}
|
||||
|
||||
echo "Number of elements: $cnt"
|
||||
for (( i = 0 ; i < cnt ; i++ ))
|
||||
do
|
||||
echo "Element [$i]: ${dest[$i]}"
|
||||
done
|
||||
|
||||
# Assign an array to a single array element (twice).
|
||||
dest[0]=${array1[@]}
|
||||
dest[1]=${array2[@]}
|
||||
|
||||
# List the result.
|
||||
echo
|
||||
echo '- - Testing modified array - -'
|
||||
cnt=${#dest[@]}
|
||||
|
||||
echo "Number of elements: $cnt"
|
||||
for (( i = 0 ; i < cnt ; i++ ))
|
||||
do
|
||||
echo "Element [$i]: ${dest[$i]}"
|
||||
done
|
||||
|
||||
# Examine the modified second element.
|
||||
echo
|
||||
echo '- - Reassign and list second element - -'
|
||||
|
||||
declare -a subArray=${dest[1]}
|
||||
cnt=${#subArray[@]}
|
||||
|
||||
echo "Number of elements: $cnt"
|
||||
for (( i = 0 ; i < cnt ; i++ ))
|
||||
do
|
||||
echo "Element [$i]: ${subArray[$i]}"
|
||||
done
|
||||
|
||||
# The assignment of an entire array to a single element
|
||||
#+ of another array using the '=${ ... }' array assignment
|
||||
#+ has converted the array being assigned into a string,
|
||||
#+ with the elements separated by a space (the first character of IFS).
|
||||
|
||||
# If the original elements didn't contain whitespace . . .
|
||||
# If the original array isn't subscript sparse . . .
|
||||
# Then we could get the original array structure back again.
|
||||
|
||||
# Restore from the modified second element.
|
||||
echo
|
||||
echo '- - Listing restored element - -'
|
||||
|
||||
declare -a subArray=( ${dest[1]} )
|
||||
cnt=${#subArray[@]}
|
||||
|
||||
echo "Number of elements: $cnt"
|
||||
for (( i = 0 ; i < cnt ; i++ ))
|
||||
do
|
||||
echo "Element [$i]: ${subArray[$i]}"
|
||||
done
|
||||
echo '- - Do not depend on this behavior. - -'
|
||||
echo '- - This behavior is subject to change - -'
|
||||
echo '- - in versions of Bash newer than version 2.05b - -'
|
||||
|
||||
# MSZ: Sorry about any earlier confusion folks.
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,64 @@
|
|||
#! /bin/bash
|
||||
# array-assign.bash
|
||||
|
||||
# Array operations are Bash specific,
|
||||
#+ hence the ".bash" in the script name.
|
||||
|
||||
# Copyright (c) Michael S. Zick, 2003, All rights reserved.
|
||||
# License: Unrestricted reuse in any form, for any purpose.
|
||||
# Version: $ID$
|
||||
|
||||
# Based on an example provided by Stephane Chazelas
|
||||
#+ which appeared in the book: Advanced Bash Scripting Guide.
|
||||
|
||||
# Output format of the 'times' command:
|
||||
# User CPU <space> System CPU
|
||||
# User CPU of dead children <space> System CPU of dead children
|
||||
|
||||
# Bash has two versions of assigning all elements of an array
|
||||
#+ to a new array variable.
|
||||
# Both drop 'null reference' elements
|
||||
#+ in Bash versions 2.04, 2.05a and 2.05b.
|
||||
# An additional array assignment that maintains the relationship of
|
||||
#+ [subscript]=value for arrays may be added to newer versions.
|
||||
|
||||
# Constructs a large array using an internal command,
|
||||
#+ but anything creating an array of several thousand elements
|
||||
#+ will do just fine.
|
||||
|
||||
declare -a bigOne=( /dev/* )
|
||||
echo
|
||||
echo 'Conditions: Unquoted, default IFS, All-Elements-Of'
|
||||
echo "Number of elements in array is ${#bigOne[@]}"
|
||||
|
||||
# set -vx
|
||||
|
||||
|
||||
|
||||
echo
|
||||
echo '- - testing: =( ${array[@]} ) - -'
|
||||
times
|
||||
declare -a bigTwo=( ${bigOne[@]} )
|
||||
# ^ ^
|
||||
times
|
||||
|
||||
echo
|
||||
echo '- - testing: =${array[@]} - -'
|
||||
times
|
||||
declare -a bigThree=${bigOne[@]}
|
||||
# No parentheses this time.
|
||||
times
|
||||
|
||||
# Comparing the numbers shows that the second form, pointed out
|
||||
#+ by Stephane Chazelas, is from three to four times faster.
|
||||
|
||||
# I will continue to use the first form in my example descriptions
|
||||
#+ because I think it is a better illustration of what is happening.
|
||||
|
||||
# The reusable portions of my examples will actual contain
|
||||
#+ the second form where appropriate because of the speedup.
|
||||
|
||||
# MSZ: Sorry about that earlier oversight folks.
|
||||
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,43 @@
|
|||
#!/bin/bash
|
||||
# array-ops.sh: More fun with arrays.
|
||||
|
||||
|
||||
array=( zero one two three four five )
|
||||
|
||||
echo ${array[0]} # zero
|
||||
echo ${array:0} # zero
|
||||
# Parameter expansion of first element,
|
||||
#+ starting at position # 0 (1st character).
|
||||
echo ${array:1} # ero
|
||||
# Parameter expansion of first element,
|
||||
#+ starting at position # 1 (2nd character).
|
||||
|
||||
echo "--------------"
|
||||
|
||||
echo ${#array[0]} # 4
|
||||
# Length of first element of array.
|
||||
echo ${#array} # 4
|
||||
# Length of first element of array.
|
||||
# (Alternate notation)
|
||||
|
||||
echo ${#array[1]} # 4
|
||||
# Length of second element of array.
|
||||
# Arrays in Bash have zero-based indexing.
|
||||
|
||||
echo ${#array[*]} # 6
|
||||
# Number of elements in array.
|
||||
echo ${#array[@]} # 6
|
||||
# Number of elements in array.
|
||||
|
||||
echo "--------------"
|
||||
|
||||
array2=( [0]="first element" [1]="second element" [3]="fourth element" )
|
||||
|
||||
echo ${array2[0]} # first element
|
||||
echo ${array2[1]} # second element
|
||||
echo ${array2[2]} #
|
||||
# Skipped in initialization, and therefore null.
|
||||
echo ${array2[3]} # fourth element
|
||||
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,104 @@
|
|||
#!/bin/bash
|
||||
# array-strops.sh: String operations on arrays.
|
||||
# Script by Michael Zick.
|
||||
# Used with permission.
|
||||
|
||||
# In general, any string operation in the ${name ... } notation
|
||||
#+ can be applied to all string elements in an array
|
||||
#+ with the ${name[@] ... } or ${name[*] ...} notation.
|
||||
|
||||
|
||||
arrayZ=( one two three four five five )
|
||||
|
||||
echo
|
||||
|
||||
# Trailing Substring Extraction
|
||||
echo ${arrayZ[@]:0} # one two three four five five
|
||||
# All elements.
|
||||
|
||||
echo ${arrayZ[@]:1} # two three four five five
|
||||
# All elements following element[0].
|
||||
|
||||
echo ${arrayZ[@]:1:2} # two three
|
||||
# Only the two elements after element[0].
|
||||
|
||||
echo "-----------------------"
|
||||
|
||||
# Substring Removal
|
||||
# Removes shortest match from front of string(s),
|
||||
#+ where the substring is a regular expression.
|
||||
|
||||
echo ${arrayZ[@]#f*r} # one two three five five
|
||||
# Applied to all elements of the array.
|
||||
# Matches "four" and removes it.
|
||||
|
||||
# Longest match from front of string(s)
|
||||
echo ${arrayZ[@]##t*e} # one two four five five
|
||||
# Applied to all elements of the array.
|
||||
# Matches "three" and removes it.
|
||||
|
||||
# Shortest match from back of string(s)
|
||||
echo ${arrayZ[@]%h*e} # one two t four five five
|
||||
# Applied to all elements of the array.
|
||||
# Matches "hree" and removes it.
|
||||
|
||||
# Longest match from back of string(s)
|
||||
echo ${arrayZ[@]%%t*e} # one two four five five
|
||||
# Applied to all elements of the array.
|
||||
# Matches "three" and removes it.
|
||||
|
||||
echo "-----------------------"
|
||||
|
||||
# Substring Replacement
|
||||
|
||||
# Replace first occurance of substring with replacement
|
||||
echo ${arrayZ[@]/fiv/XYZ} # one two three four XYZe XYZe
|
||||
# Applied to all elements of the array.
|
||||
|
||||
# Replace all occurances of substring
|
||||
echo ${arrayZ[@]//iv/YY} # one two three four fYYe fYYe
|
||||
# Applied to all elements of the array.
|
||||
|
||||
# Delete all occurances of substring
|
||||
# Not specifing a replacement means 'delete'
|
||||
echo ${arrayZ[@]//fi/} # one two three four ve ve
|
||||
# Applied to all elements of the array.
|
||||
|
||||
# Replace front-end occurances of substring
|
||||
echo ${arrayZ[@]/#fi/XY} # one two three four XYve XYve
|
||||
# Applied to all elements of the array.
|
||||
|
||||
# Replace back-end occurances of substring
|
||||
echo ${arrayZ[@]/%ve/ZZ} # one two three four fiZZ fiZZ
|
||||
# Applied to all elements of the array.
|
||||
|
||||
echo ${arrayZ[@]/%o/XX} # one twXX three four five five
|
||||
# Why?
|
||||
|
||||
echo "-----------------------"
|
||||
|
||||
|
||||
# Before reaching for awk (or anything else)
|
||||
# Recall:
|
||||
# $( ... ) is a function call.
|
||||
# Functions run as a sub-process.
|
||||
# Functions write their output to stdout.
|
||||
# Assignment reads the function's stdout.
|
||||
# The name[@] notation specifies a "for-each" operation.
|
||||
|
||||
newstr() {
|
||||
echo -n "!!!"
|
||||
}
|
||||
|
||||
echo ${arrayZ[@]/%e/$(newstr)}
|
||||
# on!!! two thre!!! four fiv!!! fiv!!!
|
||||
# Q.E.D: The replacement action is an 'assignment.'
|
||||
|
||||
# Accessing the "For-Each"
|
||||
echo ${arrayZ[@]//*/$(newstr optional_arguments)}
|
||||
# Now, if Bash would just pass the matched string as $0
|
||||
#+ to the function being called . . .
|
||||
|
||||
echo
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,999 @@
|
|||
#!/bin/bash
|
||||
# basics-reviewed.bash
|
||||
|
||||
# File extension == *.bash == specific to Bash
|
||||
|
||||
# Copyright (c) Michael S. Zick, 2003; All rights reserved.
|
||||
# License: Use in any form, for any purpose.
|
||||
# Revision: $ID$
|
||||
#
|
||||
# Edited for layout by M.C.
|
||||
# (author of the "Advanced Bash Scripting Guide")
|
||||
|
||||
|
||||
# This script tested under Bash versions 2.04, 2.05a and 2.05b.
|
||||
# It may not work with earlier versions.
|
||||
# This demonstration script generates one --intentional--
|
||||
#+ "command not found" error message. See line 394.
|
||||
|
||||
# The current Bash maintainer, Chet Ramey, has fixed the items noted
|
||||
#+ for an upcoming version of Bash.
|
||||
|
||||
|
||||
|
||||
###-------------------------------------------###
|
||||
### Pipe the output of this script to 'more' ###
|
||||
###+ else it will scroll off the page. ###
|
||||
### ###
|
||||
### You may also redirect its output ###
|
||||
###+ to a file for examination. ###
|
||||
###-------------------------------------------###
|
||||
|
||||
|
||||
|
||||
# Most of the following points are described at length in
|
||||
#+ the text of the foregoing "Advanced Bash Scripting Guide."
|
||||
# This demonstration script is mostly just a reorganized presentation.
|
||||
# -- msz
|
||||
|
||||
# Variables are not typed unless otherwise specified.
|
||||
|
||||
# Variables are named. Names must contain a non-digit.
|
||||
# File descriptor names (as in, for example: 2>&1)
|
||||
#+ contain ONLY digits.
|
||||
|
||||
# Parameters and Bash array elements are numbered.
|
||||
# (Parameters are very similar to Bash arrays.)
|
||||
|
||||
# A variable name may be undefined (null reference).
|
||||
unset VarNull
|
||||
|
||||
# A variable name may be defined but empty (null contents).
|
||||
VarEmpty='' # Two, adjacent, single quotes.
|
||||
|
||||
# A variable name my be defined and non-empty
|
||||
VarSomething='Literal'
|
||||
|
||||
# A variable may contain:
|
||||
# * A whole number as a signed 32-bit (or larger) integer
|
||||
# * A string
|
||||
# A variable may also be an array.
|
||||
|
||||
# A string may contain embedded blanks and may be treated
|
||||
#+ as if it where a function name with optional arguments.
|
||||
|
||||
# The names of variables and the names of functions
|
||||
#+ are in different namespaces.
|
||||
|
||||
|
||||
# A variable may be defined as a Bash array either explicitly or
|
||||
#+ implicitly by the syntax of the assignment statement.
|
||||
# Explicit:
|
||||
declare -a ArrayVar
|
||||
|
||||
|
||||
|
||||
# The echo command is a built-in.
|
||||
echo $VarSomething
|
||||
|
||||
# The printf command is a built-in.
|
||||
# Translate %s as: String-Format
|
||||
printf %s $VarSomething # No linebreak specified, none output.
|
||||
echo # Default, only linebreak output.
|
||||
|
||||
|
||||
|
||||
|
||||
# The Bash parser word breaks on whitespace.
|
||||
# Whitespace, or the lack of it is significant.
|
||||
# (This holds true in general; there are, of course, exceptions.)
|
||||
|
||||
|
||||
|
||||
|
||||
# Translate the DOLLAR_SIGN character as: Content-Of.
|
||||
|
||||
# Extended-Syntax way of writing Content-Of:
|
||||
echo ${VarSomething}
|
||||
|
||||
# The ${ ... } Extended-Syntax allows more than just the variable
|
||||
#+ name to be specified.
|
||||
# In general, $VarSomething can always be written as: ${VarSomething}.
|
||||
|
||||
# Call this script with arguments to see the following in action.
|
||||
|
||||
|
||||
|
||||
# Outside of double-quotes, the special characters @ and *
|
||||
#+ specify identical behavior.
|
||||
# May be pronounced as: All-Elements-Of.
|
||||
|
||||
# Without specification of a name, they refer to the
|
||||
#+ pre-defined parameter Bash-Array.
|
||||
|
||||
|
||||
|
||||
# Glob-Pattern references
|
||||
echo $* # All parameters to script or function
|
||||
echo ${*} # Same
|
||||
|
||||
# Bash disables filename expansion for Glob-Patterns.
|
||||
# Only character matching is active.
|
||||
|
||||
|
||||
# All-Elements-Of references
|
||||
echo $@ # Same as above
|
||||
echo ${@} # Same as above
|
||||
|
||||
|
||||
|
||||
|
||||
# Within double-quotes, the behavior of Glob-Pattern references
|
||||
#+ depends on the setting of IFS (Input Field Separator).
|
||||
# Within double-quotes, All-Elements-Of references behave the same.
|
||||
|
||||
|
||||
# Specifying only the name of a variable holding a string refers
|
||||
#+ to all elements (characters) of a string.
|
||||
|
||||
|
||||
# To specify an element (character) of a string,
|
||||
#+ the Extended-Syntax reference notation (see below) MAY be used.
|
||||
|
||||
|
||||
|
||||
|
||||
# Specifying only the name of a Bash array references
|
||||
#+ the subscript zero element,
|
||||
#+ NOT the FIRST DEFINED nor the FIRST WITH CONTENTS element.
|
||||
|
||||
# Additional qualification is needed to reference other elements,
|
||||
#+ which means that the reference MUST be written in Extended-Syntax.
|
||||
# The general form is: ${name[subscript]}.
|
||||
|
||||
# The string forms may also be used: ${name:subscript}
|
||||
#+ for Bash-Arrays when referencing the subscript zero element.
|
||||
|
||||
|
||||
# Bash-Arrays are implemented internally as linked lists,
|
||||
#+ not as a fixed area of storage as in some programming languages.
|
||||
|
||||
|
||||
# Characteristics of Bash arrays (Bash-Arrays):
|
||||
# --------------------------------------------
|
||||
|
||||
# If not otherwise specified, Bash-Array subscripts begin with
|
||||
#+ subscript number zero. Literally: [0]
|
||||
# This is called zero-based indexing.
|
||||
###
|
||||
# If not otherwise specified, Bash-Arrays are subscript packed
|
||||
#+ (sequential subscripts without subscript gaps).
|
||||
###
|
||||
# Negative subscripts are not allowed.
|
||||
###
|
||||
# Elements of a Bash-Array need not all be of the same type.
|
||||
###
|
||||
# Elements of a Bash-Array may be undefined (null reference).
|
||||
# That is, a Bash-Array my be "subscript sparse."
|
||||
###
|
||||
# Elements of a Bash-Array may be defined and empty (null contents).
|
||||
###
|
||||
# Elements of a Bash-Array may contain:
|
||||
# * A whole number as a signed 32-bit (or larger) integer
|
||||
# * A string
|
||||
# * A string formated so that it appears to be a function name
|
||||
# + with optional arguments
|
||||
###
|
||||
# Defined elements of a Bash-Array may be undefined (unset).
|
||||
# That is, a subscript packed Bash-Array may be changed
|
||||
# + into a subscript sparse Bash-Array.
|
||||
###
|
||||
# Elements may be added to a Bash-Array by defining an element
|
||||
#+ not previously defined.
|
||||
###
|
||||
# For these reasons, I have been calling them "Bash-Arrays".
|
||||
# I'll return to the generic term "array" from now on.
|
||||
# -- msz
|
||||
|
||||
|
||||
|
||||
|
||||
# Demo time -- initialize the previously declared ArrayVar as a
|
||||
#+ sparse array.
|
||||
# (The 'unset ... ' is just documentation here.)
|
||||
|
||||
unset ArrayVar[0] # Just for the record
|
||||
ArrayVar[1]=one # Unquoted literal
|
||||
ArrayVar[2]='' # Defined, and empty
|
||||
unset ArrayVar[3] # Just for the record
|
||||
ArrayVar[4]='four' # Quoted literal
|
||||
|
||||
|
||||
|
||||
# Translate the %q format as: Quoted-Respecting-IFS-Rules.
|
||||
echo
|
||||
echo '- - Outside of double-quotes - -'
|
||||
###
|
||||
printf %q ${ArrayVar[*]} # Glob-Pattern All-Elements-Of
|
||||
echo
|
||||
echo 'echo command:'${ArrayVar[*]}
|
||||
###
|
||||
printf %q ${ArrayVar[@]} # All-Elements-Of
|
||||
echo
|
||||
echo 'echo command:'${ArrayVar[@]}
|
||||
|
||||
# The use of double-quotes may be translated as: Enable-Substitution.
|
||||
|
||||
# There are five cases recognized for the IFS setting.
|
||||
|
||||
echo
|
||||
echo '- - Within double-quotes - Default IFS of space-tab-newline - -'
|
||||
IFS=$'\x20'$'\x09'$'\x0A' # These three bytes,
|
||||
#+ in exactly this order.
|
||||
|
||||
|
||||
printf %q "${ArrayVar[*]}" # Glob-Pattern All-Elements-Of
|
||||
echo
|
||||
echo 'echo command:'"${ArrayVar[*]}"
|
||||
###
|
||||
printf %q "${ArrayVar[@]}" # All-Elements-Of
|
||||
echo
|
||||
echo 'echo command:'"${ArrayVar[@]}"
|
||||
|
||||
|
||||
echo
|
||||
echo '- - Within double-quotes - First character of IFS is ^ - -'
|
||||
# Any printing, non-whitespace character should do the same.
|
||||
IFS='^'$IFS # ^ + space tab newline
|
||||
###
|
||||
printf %q "${ArrayVar[*]}" # Glob-Pattern All-Elements-Of
|
||||
echo
|
||||
echo 'echo command:'"${ArrayVar[*]}"
|
||||
###
|
||||
printf %q "${ArrayVar[@]}" # All-Elements-Of
|
||||
echo
|
||||
echo 'echo command:'"${ArrayVar[@]}"
|
||||
|
||||
|
||||
echo
|
||||
echo '- - Within double-quotes - Without whitespace in IFS - -'
|
||||
IFS='^:%!'
|
||||
###
|
||||
printf %q "${ArrayVar[*]}" # Glob-Pattern All-Elements-Of
|
||||
echo
|
||||
echo 'echo command:'"${ArrayVar[*]}"
|
||||
###
|
||||
printf %q "${ArrayVar[@]}" # All-Elements-Of
|
||||
echo
|
||||
echo 'echo command:'"${ArrayVar[@]}"
|
||||
|
||||
|
||||
echo
|
||||
echo '- - Within double-quotes - IFS set and empty - -'
|
||||
IFS=''
|
||||
###
|
||||
printf %q "${ArrayVar[*]}" # Glob-Pattern All-Elements-Of
|
||||
echo
|
||||
echo 'echo command:'"${ArrayVar[*]}"
|
||||
###
|
||||
printf %q "${ArrayVar[@]}" # All-Elements-Of
|
||||
echo
|
||||
echo 'echo command:'"${ArrayVar[@]}"
|
||||
|
||||
|
||||
echo
|
||||
echo '- - Within double-quotes - IFS undefined - -'
|
||||
unset IFS
|
||||
###
|
||||
printf %q "${ArrayVar[*]}" # Glob-Pattern All-Elements-Of
|
||||
echo
|
||||
echo 'echo command:'"${ArrayVar[*]}"
|
||||
###
|
||||
printf %q "${ArrayVar[@]}" # All-Elements-Of
|
||||
echo
|
||||
echo 'echo command:'"${ArrayVar[@]}"
|
||||
|
||||
|
||||
# Put IFS back to the default.
|
||||
# Default is exactly these three bytes.
|
||||
IFS=$'\x20'$'\x09'$'\x0A' # In exactly this order.
|
||||
|
||||
# Interpretation of the above outputs:
|
||||
# A Glob-Pattern is I/O; the setting of IFS matters.
|
||||
###
|
||||
# An All-Elements-Of does not consider IFS settings.
|
||||
###
|
||||
# Note the different output using the echo command and the
|
||||
#+ quoted format operator of the printf command.
|
||||
|
||||
|
||||
# Recall:
|
||||
# Parameters are similar to arrays and have the similar behaviors.
|
||||
###
|
||||
# The above examples demonstrate the possible variations.
|
||||
# To retain the shape of a sparse array, additional script
|
||||
#+ programming is required.
|
||||
###
|
||||
# The source code of Bash has a routine to output the
|
||||
#+ [subscript]=value array assignment format.
|
||||
# As of version 2.05b, that routine is not used,
|
||||
#+ but that might change in future releases.
|
||||
|
||||
|
||||
|
||||
# The length of a string, measured in non-null elements (characters):
|
||||
echo
|
||||
echo '- - Non-quoted references - -'
|
||||
echo 'Non-Null character count: '${#VarSomething}' characters.'
|
||||
|
||||
# test='Lit'$'\x00''eral' # $'\x00' is a null character.
|
||||
# echo ${#test} # See that?
|
||||
|
||||
|
||||
|
||||
# The length of an array, measured in defined elements,
|
||||
#+ including null content elements.
|
||||
echo
|
||||
echo 'Defined content count: '${#ArrayVar[@]}' elements.'
|
||||
# That is NOT the maximum subscript (4).
|
||||
# That is NOT the range of the subscripts (1 . . 4 inclusive).
|
||||
# It IS the length of the linked list.
|
||||
###
|
||||
# Both the maximum subscript and the range of the subscripts may
|
||||
#+ be found with additional script programming.
|
||||
|
||||
# The length of a string, measured in non-null elements (characters):
|
||||
echo
|
||||
echo '- - Quoted, Glob-Pattern references - -'
|
||||
echo 'Non-Null character count: '"${#VarSomething}"' characters.'
|
||||
|
||||
# The length of an array, measured in defined elements,
|
||||
#+ including null-content elements.
|
||||
echo
|
||||
echo 'Defined element count: '"${#ArrayVar[*]}"' elements.'
|
||||
|
||||
# Interpretation: Substitution does not effect the ${# ... } operation.
|
||||
# Suggestion:
|
||||
# Always use the All-Elements-Of character
|
||||
#+ if that is what is intended (independence from IFS).
|
||||
|
||||
|
||||
|
||||
# Define a simple function.
|
||||
# I include an underscore in the name
|
||||
#+ to make it distinctive in the examples below.
|
||||
###
|
||||
# Bash separates variable names and function names
|
||||
#+ in different namespaces.
|
||||
# The Mark-One eyeball isn't that advanced.
|
||||
###
|
||||
_simple() {
|
||||
echo -n 'SimpleFunc'$@ # Newlines are swallowed in
|
||||
} #+ result returned in any case.
|
||||
|
||||
|
||||
# The ( ... ) notation invokes a command or function.
|
||||
# The $( ... ) notation is pronounced: Result-Of.
|
||||
|
||||
|
||||
# Invoke the function _simple
|
||||
echo
|
||||
echo '- - Output of function _simple - -'
|
||||
_simple # Try passing arguments.
|
||||
echo
|
||||
# or
|
||||
(_simple) # Try passing arguments.
|
||||
echo
|
||||
|
||||
echo '- Is there a variable of that name? -'
|
||||
echo $_simple not defined # No variable by that name.
|
||||
|
||||
# Invoke the result of function _simple (Error msg intended)
|
||||
|
||||
###
|
||||
$(_simple) # Gives an error message:
|
||||
# line 394: SimpleFunc: command not found
|
||||
# ---------------------------------------
|
||||
|
||||
echo
|
||||
###
|
||||
|
||||
# The first word of the result of function _simple
|
||||
#+ is neither a valid Bash command nor the name of a defined function.
|
||||
###
|
||||
# This demonstrates that the output of _simple is subject to evaluation.
|
||||
###
|
||||
# Interpretation:
|
||||
# A function can be used to generate in-line Bash commands.
|
||||
|
||||
|
||||
# A simple function where the first word of result IS a bash command:
|
||||
###
|
||||
_print() {
|
||||
echo -n 'printf %q '$@
|
||||
}
|
||||
|
||||
echo '- - Outputs of function _print - -'
|
||||
_print parm1 parm2 # An Output NOT A Command.
|
||||
echo
|
||||
|
||||
$(_print parm1 parm2) # Executes: printf %q parm1 parm2
|
||||
# See above IFS examples for the
|
||||
#+ various possibilities.
|
||||
echo
|
||||
|
||||
$(_print $VarSomething) # The predictable result.
|
||||
echo
|
||||
|
||||
|
||||
|
||||
# Function variables
|
||||
# ------------------
|
||||
|
||||
echo
|
||||
echo '- - Function variables - -'
|
||||
# A variable may represent a signed integer, a string or an array.
|
||||
# A string may be used like a function name with optional arguments.
|
||||
|
||||
# set -vx # Enable if desired
|
||||
declare -f funcVar #+ in namespace of functions
|
||||
|
||||
funcVar=_print # Contains name of function.
|
||||
$funcVar parm1 # Same as _print at this point.
|
||||
echo
|
||||
|
||||
funcVar=$(_print ) # Contains result of function.
|
||||
$funcVar # No input, No output.
|
||||
$funcVar $VarSomething # The predictable result.
|
||||
echo
|
||||
|
||||
funcVar=$(_print $VarSomething) # $VarSomething replaced HERE.
|
||||
$funcVar # The expansion is part of the
|
||||
echo #+ variable contents.
|
||||
|
||||
funcVar="$(_print $VarSomething)" # $VarSomething replaced HERE.
|
||||
$funcVar # The expansion is part of the
|
||||
echo #+ variable contents.
|
||||
|
||||
# The difference between the unquoted and the double-quoted versions
|
||||
#+ above can be seen in the "protect_literal.sh" example.
|
||||
# The first case above is processed as two, unquoted, Bash-Words.
|
||||
# The second case above is processed as one, quoted, Bash-Word.
|
||||
|
||||
|
||||
|
||||
|
||||
# Delayed replacement
|
||||
# -------------------
|
||||
|
||||
echo
|
||||
echo '- - Delayed replacement - -'
|
||||
funcVar="$(_print '$VarSomething')" # No replacement, single Bash-Word.
|
||||
eval $funcVar # $VarSomething replaced HERE.
|
||||
echo
|
||||
|
||||
VarSomething='NewThing'
|
||||
eval $funcVar # $VarSomething replaced HERE.
|
||||
echo
|
||||
|
||||
# Restore the original setting trashed above.
|
||||
VarSomething=Literal
|
||||
|
||||
# There are a pair of functions demonstrated in the
|
||||
#+ "protect_literal.sh" and "unprotect_literal.sh" examples.
|
||||
# These are general purpose functions for delayed replacement literals
|
||||
#+ containing variables.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# REVIEW:
|
||||
# ------
|
||||
|
||||
# A string can be considered a Classic-Array of elements (characters).
|
||||
# A string operation applies to all elements (characters) of the string
|
||||
#+ (in concept, anyway).
|
||||
###
|
||||
# The notation: ${array_name[@]} represents all elements of the
|
||||
#+ Bash-Array: array_name.
|
||||
###
|
||||
# The Extended-Syntax string operations can be applied to all
|
||||
#+ elements of an array.
|
||||
###
|
||||
# This may be thought of as a For-Each operation on a vector of strings.
|
||||
###
|
||||
# Parameters are similar to an array.
|
||||
# The initialization of a parameter array for a script
|
||||
#+ and a parameter array for a function only differ
|
||||
#+ in the initialization of ${0}, which never changes its setting.
|
||||
###
|
||||
# Subscript zero of the script's parameter array contains
|
||||
#+ the name of the script.
|
||||
###
|
||||
# Subscript zero of a function's parameter array DOES NOT contain
|
||||
#+ the name of the function.
|
||||
# The name of the current function is accessed by the $FUNCNAME variable.
|
||||
###
|
||||
# A quick, review list follows (quick, not short).
|
||||
|
||||
echo
|
||||
echo '- - Test (but not change) - -'
|
||||
echo '- null reference -'
|
||||
echo -n ${VarNull-'NotSet'}' ' # NotSet
|
||||
echo ${VarNull} # NewLine only
|
||||
echo -n ${VarNull:-'NotSet'}' ' # NotSet
|
||||
echo ${VarNull} # Newline only
|
||||
|
||||
echo '- null contents -'
|
||||
echo -n ${VarEmpty-'Empty'}' ' # Only the space
|
||||
echo ${VarEmpty} # Newline only
|
||||
echo -n ${VarEmpty:-'Empty'}' ' # Empty
|
||||
echo ${VarEmpty} # Newline only
|
||||
|
||||
echo '- contents -'
|
||||
echo ${VarSomething-'Content'} # Literal
|
||||
echo ${VarSomething:-'Content'} # Literal
|
||||
|
||||
echo '- Sparse Array -'
|
||||
echo ${ArrayVar[@]-'not set'}
|
||||
|
||||
# ASCII-Art time
|
||||
# State Y==yes, N==no
|
||||
# - :-
|
||||
# Unset Y Y ${# ... } == 0
|
||||
# Empty N Y ${# ... } == 0
|
||||
# Contents N N ${# ... } > 0
|
||||
|
||||
# Either the first and/or the second part of the tests
|
||||
#+ may be a command or a function invocation string.
|
||||
echo
|
||||
echo '- - Test 1 for undefined - -'
|
||||
declare -i t
|
||||
_decT() {
|
||||
t=$t-1
|
||||
}
|
||||
|
||||
# Null reference, set: t == -1
|
||||
t=${#VarNull} # Results in zero.
|
||||
${VarNull- _decT } # Function executes, t now -1.
|
||||
echo $t
|
||||
|
||||
# Null contents, set: t == 0
|
||||
t=${#VarEmpty} # Results in zero.
|
||||
${VarEmpty- _decT } # _decT function NOT executed.
|
||||
echo $t
|
||||
|
||||
# Contents, set: t == number of non-null characters
|
||||
VarSomething='_simple' # Set to valid function name.
|
||||
t=${#VarSomething} # non-zero length
|
||||
${VarSomething- _decT } # Function _simple executed.
|
||||
echo $t # Note the Append-To action.
|
||||
|
||||
# Exercise: clean up that example.
|
||||
unset t
|
||||
unset _decT
|
||||
VarSomething=Literal
|
||||
|
||||
echo
|
||||
echo '- - Test and Change - -'
|
||||
echo '- Assignment if null reference -'
|
||||
echo -n ${VarNull='NotSet'}' ' # NotSet NotSet
|
||||
echo ${VarNull}
|
||||
unset VarNull
|
||||
|
||||
echo '- Assignment if null reference -'
|
||||
echo -n ${VarNull:='NotSet'}' ' # NotSet NotSet
|
||||
echo ${VarNull}
|
||||
unset VarNull
|
||||
|
||||
echo '- No assignment if null contents -'
|
||||
echo -n ${VarEmpty='Empty'}' ' # Space only
|
||||
echo ${VarEmpty}
|
||||
VarEmpty=''
|
||||
|
||||
echo '- Assignment if null contents -'
|
||||
echo -n ${VarEmpty:='Empty'}' ' # Empty Empty
|
||||
echo ${VarEmpty}
|
||||
VarEmpty=''
|
||||
|
||||
echo '- No change if already has contents -'
|
||||
echo ${VarSomething='Content'} # Literal
|
||||
echo ${VarSomething:='Content'} # Literal
|
||||
|
||||
|
||||
# "Subscript sparse" Bash-Arrays
|
||||
###
|
||||
# Bash-Arrays are subscript packed, beginning with
|
||||
#+ subscript zero unless otherwise specified.
|
||||
###
|
||||
# The initialization of ArrayVar was one way
|
||||
#+ to "otherwise specify". Here is the other way:
|
||||
###
|
||||
echo
|
||||
declare -a ArraySparse
|
||||
ArraySparse=( [1]=one [2]='' [4]='four' )
|
||||
# [0]=null reference, [2]=null content, [3]=null reference
|
||||
|
||||
echo '- - Array-Sparse List - -'
|
||||
# Within double-quotes, default IFS, Glob-Pattern
|
||||
|
||||
IFS=$'\x20'$'\x09'$'\x0A'
|
||||
printf %q "${ArraySparse[*]}"
|
||||
echo
|
||||
|
||||
# Note that the output does not distinguish between "null content"
|
||||
#+ and "null reference".
|
||||
# Both print as escaped whitespace.
|
||||
###
|
||||
# Note also that the output does NOT contain escaped whitespace
|
||||
#+ for the "null reference(s)" prior to the first defined element.
|
||||
###
|
||||
# This behavior of 2.04, 2.05a and 2.05b has been reported
|
||||
#+ and may change in a future version of Bash.
|
||||
|
||||
# To output a sparse array and maintain the [subscript]=value
|
||||
#+ relationship without change requires a bit of programming.
|
||||
# One possible code fragment:
|
||||
###
|
||||
# local l=${#ArraySparse[@]} # Count of defined elements
|
||||
# local f=0 # Count of found subscripts
|
||||
# local i=0 # Subscript to test
|
||||
( # Anonymous in-line function
|
||||
for (( l=${#ArraySparse[@]}, f = 0, i = 0 ; f < l ; i++ ))
|
||||
do
|
||||
# 'if defined then...'
|
||||
${ArraySparse[$i]+ eval echo '\ ['$i']='${ArraySparse[$i]} ; (( f++ )) }
|
||||
done
|
||||
)
|
||||
|
||||
# The reader coming upon the above code fragment cold
|
||||
#+ might want to review "command lists" and "multiple commands on a line"
|
||||
#+ in the text of the foregoing "Advanced Bash Scripting Guide."
|
||||
###
|
||||
# Note:
|
||||
# The "read -a array_name" version of the "read" command
|
||||
#+ begins filling array_name at subscript zero.
|
||||
# ArraySparse does not define a value at subscript zero.
|
||||
###
|
||||
# The user needing to read/write a sparse array to either
|
||||
#+ external storage or a communications socket must invent
|
||||
#+ a read/write code pair suitable for their purpose.
|
||||
###
|
||||
# Exercise: clean it up.
|
||||
|
||||
unset ArraySparse
|
||||
|
||||
echo
|
||||
echo '- - Conditional alternate (But not change)- -'
|
||||
echo '- No alternate if null reference -'
|
||||
echo -n ${VarNull+'NotSet'}' '
|
||||
echo ${VarNull}
|
||||
unset VarNull
|
||||
|
||||
echo '- No alternate if null reference -'
|
||||
echo -n ${VarNull:+'NotSet'}' '
|
||||
echo ${VarNull}
|
||||
unset VarNull
|
||||
|
||||
echo '- Alternate if null contents -'
|
||||
echo -n ${VarEmpty+'Empty'}' ' # Empty
|
||||
echo ${VarEmpty}
|
||||
VarEmpty=''
|
||||
|
||||
echo '- No alternate if null contents -'
|
||||
echo -n ${VarEmpty:+'Empty'}' ' # Space only
|
||||
echo ${VarEmpty}
|
||||
VarEmpty=''
|
||||
|
||||
echo '- Alternate if already has contents -'
|
||||
|
||||
# Alternate literal
|
||||
echo -n ${VarSomething+'Content'}' ' # Content Literal
|
||||
echo ${VarSomething}
|
||||
|
||||
# Invoke function
|
||||
echo -n ${VarSomething:+ $(_simple) }' ' # SimpleFunc Literal
|
||||
echo ${VarSomething}
|
||||
echo
|
||||
|
||||
echo '- - Sparse Array - -'
|
||||
echo ${ArrayVar[@]+'Empty'} # An array of 'Empty'(ies)
|
||||
echo
|
||||
|
||||
echo '- - Test 2 for undefined - -'
|
||||
|
||||
declare -i t
|
||||
_incT() {
|
||||
t=$t+1
|
||||
}
|
||||
|
||||
# Note:
|
||||
# This is the same test used in the sparse array
|
||||
#+ listing code fragment.
|
||||
|
||||
# Null reference, set: t == -1
|
||||
t=${#VarNull}-1 # Results in minus-one.
|
||||
${VarNull+ _incT } # Does not execute.
|
||||
echo $t' Null reference'
|
||||
|
||||
# Null contents, set: t == 0
|
||||
t=${#VarEmpty}-1 # Results in minus-one.
|
||||
${VarEmpty+ _incT } # Executes.
|
||||
echo $t' Null content'
|
||||
|
||||
# Contents, set: t == (number of non-null characters)
|
||||
t=${#VarSomething}-1 # non-null length minus-one
|
||||
${VarSomething+ _incT } # Executes.
|
||||
echo $t' Contents'
|
||||
|
||||
# Exercise: clean up that example.
|
||||
unset t
|
||||
unset _incT
|
||||
|
||||
# ${name?err_msg} ${name:?err_msg}
|
||||
# These follow the same rules but always exit afterwards
|
||||
#+ if an action is specified following the question mark.
|
||||
# The action following the question mark may be a literal
|
||||
#+ or a function result.
|
||||
###
|
||||
# ${name?} ${name:?} are test-only, the return can be tested.
|
||||
|
||||
|
||||
|
||||
|
||||
# Element operations
|
||||
# ------------------
|
||||
|
||||
echo
|
||||
echo '- - Trailing sub-element selection - -'
|
||||
|
||||
# Strings, Arrays and Positional parameters
|
||||
|
||||
# Call this script with multiple arguments
|
||||
#+ to see the parameter selections.
|
||||
|
||||
echo '- All -'
|
||||
echo ${VarSomething:0} # all non-null characters
|
||||
echo ${ArrayVar[@]:0} # all elements with content
|
||||
echo ${@:0} # all parameters with content;
|
||||
# ignoring parameter[0]
|
||||
|
||||
echo
|
||||
echo '- All after -'
|
||||
echo ${VarSomething:1} # all non-null after character[0]
|
||||
echo ${ArrayVar[@]:1} # all after element[0] with content
|
||||
echo ${@:2} # all after param[1] with content
|
||||
|
||||
echo
|
||||
echo '- Range after -'
|
||||
echo ${VarSomething:4:3} # ral
|
||||
# Three characters after
|
||||
# character[3]
|
||||
|
||||
echo '- Sparse array gotch -'
|
||||
echo ${ArrayVar[@]:1:2} # four - The only element with content.
|
||||
# Two elements after (if that many exist).
|
||||
# the FIRST WITH CONTENTS
|
||||
#+ (the FIRST WITH CONTENTS is being
|
||||
#+ considered as if it
|
||||
#+ were subscript zero).
|
||||
# Executed as if Bash considers ONLY array elements with CONTENT
|
||||
# printf %q "${ArrayVar[@]:0:3}" # Try this one
|
||||
|
||||
# In versions 2.04, 2.05a and 2.05b,
|
||||
#+ Bash does not handle sparse arrays as expected using this notation.
|
||||
#
|
||||
# The current Bash maintainer, Chet Ramey, has corrected this
|
||||
#+ for an upcoming version of Bash.
|
||||
|
||||
|
||||
echo '- Non-sparse array -'
|
||||
echo ${@:2:2} # Two parameters following parameter[1]
|
||||
|
||||
# New victims for string vector examples:
|
||||
stringZ=abcABC123ABCabc
|
||||
arrayZ=( abcabc ABCABC 123123 ABCABC abcabc )
|
||||
sparseZ=( [1]='abcabc' [3]='ABCABC' [4]='' [5]='123123' )
|
||||
|
||||
echo
|
||||
echo ' - - Victim string - -'$stringZ'- - '
|
||||
echo ' - - Victim array - -'${arrayZ[@]}'- - '
|
||||
echo ' - - Sparse array - -'${sparseZ[@]}'- - '
|
||||
echo ' - [0]==null ref, [2]==null ref, [4]==null content - '
|
||||
echo ' - [1]=abcabc [3]=ABCABC [5]=123123 - '
|
||||
echo ' - non-null-reference count: '${#sparseZ[@]}' elements'
|
||||
|
||||
echo
|
||||
echo '- - Prefix sub-element removal - -'
|
||||
echo '- - Glob-Pattern match must include the first character. - -'
|
||||
echo '- - Glob-Pattern may be a literal or a function result. - -'
|
||||
echo
|
||||
|
||||
|
||||
# Function returning a simple, Literal, Glob-Pattern
|
||||
_abc() {
|
||||
echo -n 'abc'
|
||||
}
|
||||
|
||||
echo '- Shortest prefix -'
|
||||
echo ${stringZ#123} # Unchanged (not a prefix).
|
||||
echo ${stringZ#$(_abc)} # ABC123ABCabc
|
||||
echo ${arrayZ[@]#abc} # Applied to each element.
|
||||
|
||||
# Fixed by Chet Ramey for an upcoming version of Bash.
|
||||
# echo ${sparseZ[@]#abc} # Version-2.05b core dumps.
|
||||
|
||||
# The -it would be nice- First-Subscript-Of
|
||||
# echo ${#sparseZ[@]#*} # This is NOT valid Bash.
|
||||
|
||||
echo
|
||||
echo '- Longest prefix -'
|
||||
echo ${stringZ##1*3} # Unchanged (not a prefix)
|
||||
echo ${stringZ##a*C} # abc
|
||||
echo ${arrayZ[@]##a*c} # ABCABC 123123 ABCABC
|
||||
|
||||
# Fixed by Chet Ramey for an upcoming version of Bash
|
||||
# echo ${sparseZ[@]##a*c} # Version-2.05b core dumps.
|
||||
|
||||
echo
|
||||
echo '- - Suffix sub-element removal - -'
|
||||
echo '- - Glob-Pattern match must include the last character. - -'
|
||||
echo '- - Glob-Pattern may be a literal or a function result. - -'
|
||||
echo
|
||||
echo '- Shortest suffix -'
|
||||
echo ${stringZ%1*3} # Unchanged (not a suffix).
|
||||
echo ${stringZ%$(_abc)} # abcABC123ABC
|
||||
echo ${arrayZ[@]%abc} # Applied to each element.
|
||||
|
||||
# Fixed by Chet Ramey for an upcoming version of Bash.
|
||||
# echo ${sparseZ[@]%abc} # Version-2.05b core dumps.
|
||||
|
||||
# The -it would be nice- Last-Subscript-Of
|
||||
# echo ${#sparseZ[@]%*} # This is NOT valid Bash.
|
||||
|
||||
echo
|
||||
echo '- Longest suffix -'
|
||||
echo ${stringZ%%1*3} # Unchanged (not a suffix)
|
||||
echo ${stringZ%%b*c} # a
|
||||
echo ${arrayZ[@]%%b*c} # a ABCABC 123123 ABCABC a
|
||||
|
||||
# Fixed by Chet Ramey for an upcoming version of Bash.
|
||||
# echo ${sparseZ[@]%%b*c} # Version-2.05b core dumps.
|
||||
|
||||
echo
|
||||
echo '- - Sub-element replacement - -'
|
||||
echo '- - Sub-element at any location in string. - -'
|
||||
echo '- - First specification is a Glob-Pattern - -'
|
||||
echo '- - Glob-Pattern may be a literal or Glob-Pattern function result. - -'
|
||||
echo '- - Second specification may be a literal or function result. - -'
|
||||
echo '- - Second specification may be unspecified. Pronounce that'
|
||||
echo ' as: Replace-With-Nothing (Delete) - -'
|
||||
echo
|
||||
|
||||
|
||||
|
||||
# Function returning a simple, Literal, Glob-Pattern
|
||||
_123() {
|
||||
echo -n '123'
|
||||
}
|
||||
|
||||
echo '- Replace first occurrence -'
|
||||
echo ${stringZ/$(_123)/999} # Changed (123 is a component).
|
||||
echo ${stringZ/ABC/xyz} # xyzABC123ABCabc
|
||||
echo ${arrayZ[@]/ABC/xyz} # Applied to each element.
|
||||
echo ${sparseZ[@]/ABC/xyz} # Works as expected.
|
||||
|
||||
echo
|
||||
echo '- Delete first occurrence -'
|
||||
echo ${stringZ/$(_123)/}
|
||||
echo ${stringZ/ABC/}
|
||||
echo ${arrayZ[@]/ABC/}
|
||||
echo ${sparseZ[@]/ABC/}
|
||||
|
||||
# The replacement need not be a literal,
|
||||
#+ since the result of a function invocation is allowed.
|
||||
# This is general to all forms of replacement.
|
||||
echo
|
||||
echo '- Replace first occurrence with Result-Of -'
|
||||
echo ${stringZ/$(_123)/$(_simple)} # Works as expected.
|
||||
echo ${arrayZ[@]/ca/$(_simple)} # Applied to each element.
|
||||
echo ${sparseZ[@]/ca/$(_simple)} # Works as expected.
|
||||
|
||||
echo
|
||||
echo '- Replace all occurrences -'
|
||||
echo ${stringZ//[b2]/X} # X-out b's and 2's
|
||||
echo ${stringZ//abc/xyz} # xyzABC123ABCxyz
|
||||
echo ${arrayZ[@]//abc/xyz} # Applied to each element.
|
||||
echo ${sparseZ[@]//abc/xyz} # Works as expected.
|
||||
|
||||
echo
|
||||
echo '- Delete all occurrences -'
|
||||
echo ${stringZ//[b2]/}
|
||||
echo ${stringZ//abc/}
|
||||
echo ${arrayZ[@]//abc/}
|
||||
echo ${sparseZ[@]//abc/}
|
||||
|
||||
echo
|
||||
echo '- - Prefix sub-element replacement - -'
|
||||
echo '- - Match must include the first character. - -'
|
||||
echo
|
||||
|
||||
echo '- Replace prefix occurrences -'
|
||||
echo ${stringZ/#[b2]/X} # Unchanged (neither is a prefix).
|
||||
echo ${stringZ/#$(_abc)/XYZ} # XYZABC123ABCabc
|
||||
echo ${arrayZ[@]/#abc/XYZ} # Applied to each element.
|
||||
echo ${sparseZ[@]/#abc/XYZ} # Works as expected.
|
||||
|
||||
echo
|
||||
echo '- Delete prefix occurrences -'
|
||||
echo ${stringZ/#[b2]/}
|
||||
echo ${stringZ/#$(_abc)/}
|
||||
echo ${arrayZ[@]/#abc/}
|
||||
echo ${sparseZ[@]/#abc/}
|
||||
|
||||
echo
|
||||
echo '- - Suffix sub-element replacement - -'
|
||||
echo '- - Match must include the last character. - -'
|
||||
echo
|
||||
|
||||
echo '- Replace suffix occurrences -'
|
||||
echo ${stringZ/%[b2]/X} # Unchanged (neither is a suffix).
|
||||
echo ${stringZ/%$(_abc)/XYZ} # abcABC123ABCXYZ
|
||||
echo ${arrayZ[@]/%abc/XYZ} # Applied to each element.
|
||||
echo ${sparseZ[@]/%abc/XYZ} # Works as expected.
|
||||
|
||||
echo
|
||||
echo '- Delete suffix occurrences -'
|
||||
echo ${stringZ/%[b2]/}
|
||||
echo ${stringZ/%$(_abc)/}
|
||||
echo ${arrayZ[@]/%abc/}
|
||||
echo ${sparseZ[@]/%abc/}
|
||||
|
||||
echo
|
||||
echo '- - Special cases of null Glob-Pattern - -'
|
||||
echo
|
||||
|
||||
echo '- Prefix all -'
|
||||
# null substring pattern means 'prefix'
|
||||
echo ${stringZ/#/NEW} # NEWabcABC123ABCabc
|
||||
echo ${arrayZ[@]/#/NEW} # Applied to each element.
|
||||
echo ${sparseZ[@]/#/NEW} # Applied to null-content also.
|
||||
# That seems reasonable.
|
||||
|
||||
echo
|
||||
echo '- Suffix all -'
|
||||
# null substring pattern means 'suffix'
|
||||
echo ${stringZ/%/NEW} # abcABC123ABCabcNEW
|
||||
echo ${arrayZ[@]/%/NEW} # Applied to each element.
|
||||
echo ${sparseZ[@]/%/NEW} # Applied to null-content also.
|
||||
# That seems reasonable.
|
||||
|
||||
echo
|
||||
echo '- - Special case For-Each Glob-Pattern - -'
|
||||
echo '- - - - This is a nice-to-have dream - - - -'
|
||||
echo
|
||||
|
||||
_GenFunc() {
|
||||
echo -n ${0} # Illustration only.
|
||||
# Actually, that would be an arbitrary computation.
|
||||
}
|
||||
|
||||
# All occurrences, matching the AnyThing pattern.
|
||||
# Currently //*/ does not match null-content nor null-reference.
|
||||
# /#/ and /%/ does match null-content but not null-reference.
|
||||
echo ${sparseZ[@]//*/$(_GenFunc)}
|
||||
|
||||
|
||||
# A possible syntax would be to make
|
||||
#+ the parameter notation used within this construct mean:
|
||||
# ${1} - The full element
|
||||
# ${2} - The prefix, if any, to the matched sub-element
|
||||
# ${3} - The matched sub-element
|
||||
# ${4} - The suffix, if any, to the matched sub-element
|
||||
#
|
||||
# echo ${sparseZ[@]//*/$(_GenFunc ${3})} # Same as ${1} here.
|
||||
# Perhaps it will be implemented in a future version of Bash.
|
||||
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,60 @@
|
|||
#! /bin/sh
|
||||
# letter-count.sh: Counting letter occurrences in a text file.
|
||||
#
|
||||
# Script by nyal (nyal@voila.fr).
|
||||
# Used with permission.
|
||||
# Recommented by document author.
|
||||
|
||||
|
||||
INIT_TAB_AWK=""
|
||||
# Parameter to initialize awk script.
|
||||
count_case=0
|
||||
FILE_PARSE=$1
|
||||
|
||||
E_PARAMERR=65
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "Usage: letter-count.sh file letters" 2>&1
|
||||
# For example: ./letter-count.sh filename.txt a b c
|
||||
exit $E_PARAMERR # Not enough arguments passed to script.
|
||||
}
|
||||
|
||||
if [ ! -f "$1" ] ; then
|
||||
echo "$1: No such file." 2>&1
|
||||
usage
|
||||
fi
|
||||
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$2: No letters specified." 2>&1
|
||||
usage
|
||||
fi
|
||||
|
||||
shift # Letters specified.
|
||||
for letter in `echo $@` # For each one . . .
|
||||
do
|
||||
INIT_TAB_AWK="$INIT_TAB_AWK tab_search[${count_case}] = \"$letter\"; final_tab[${count_case}] = 0; "
|
||||
# Pass as parameter to awk script below.
|
||||
count_case=`expr $count_case + 1`
|
||||
done
|
||||
|
||||
# DEBUG:
|
||||
# echo $INIT_TAB_AWK;
|
||||
|
||||
cat $FILE_PARSE |
|
||||
# Pipe the target file to 'awk.'
|
||||
|
||||
#--------------------------------------------------------------------------------
|
||||
awk -v tab_search=0 -v final_tab=0 -v tab=0 -v nb_letter=0 -v chara=0 -v chara2=0 \
|
||||
"BEGIN { $INIT_TAB_AWK } \
|
||||
{ split(\$0, tab, \"\"); \
|
||||
for (chara in tab) \
|
||||
{ for (chara2 in tab_search) \
|
||||
{ if (tab_search[chara2] == tab[chara]) { final_tab[chara2]++ } } } } \
|
||||
END { for (chara in final_tab) \
|
||||
{ print tab_search[chara] \" => \" final_tab[chara] } }"
|
||||
#--------------------------------------------------------------------------------
|
||||
# Nothing all that complicated, just . . .
|
||||
#+ for-loops, if-tests, and a couple of specialized functions.
|
||||
|
||||
exit $?
|
|
@ -0,0 +1,148 @@
|
|||
#! /bin/bash
|
||||
# protect_literal.sh
|
||||
|
||||
# set -vx
|
||||
|
||||
:<<-'_Protect_Literal_String_Doc'
|
||||
|
||||
Copyright (c) Michael S. Zick, 2003; All Rights Reserved
|
||||
License: Unrestricted reuse in any form, for any purpose.
|
||||
Warranty: None
|
||||
Revision: $ID$
|
||||
|
||||
Documentation redirected to the Bash no-operation.
|
||||
Bash will '/dev/null' this block when the script is first read.
|
||||
(Uncomment the above set command to see this action.)
|
||||
|
||||
Remove the first (Sha-Bang) line when sourcing this as a library
|
||||
procedure. Also comment out the example use code in the two
|
||||
places where shown.
|
||||
|
||||
|
||||
Usage:
|
||||
_protect_literal_str 'Whatever string meets your ${fancy}'
|
||||
Just echos the argument to standard out, hard quotes
|
||||
restored.
|
||||
|
||||
$(_protect_literal_str 'Whatever string meets your ${fancy}')
|
||||
as the right-hand-side of an assignment statement.
|
||||
|
||||
Does:
|
||||
As the right-hand-side of an assignment, preserves the
|
||||
hard quotes protecting the contents of the literal during
|
||||
assignment.
|
||||
|
||||
Notes:
|
||||
The strange names (_*) are used to avoid trampling on
|
||||
the user's chosen names when this is sourced as a
|
||||
library.
|
||||
|
||||
_Protect_Literal_String_Doc
|
||||
|
||||
# The 'for illustration' function form
|
||||
|
||||
_protect_literal_str() {
|
||||
|
||||
# Pick an un-used, non-printing character as local IFS.
|
||||
# Not required, but shows that we are ignoring it.
|
||||
local IFS=$'\x1B' # \ESC character
|
||||
|
||||
# Enclose the All-Elements-Of in hard quotes during assignment.
|
||||
local tmp=$'\x27'$@$'\x27'
|
||||
# local tmp=$'\''$@$'\'' # Even uglier.
|
||||
|
||||
local len=${#tmp} # Info only.
|
||||
echo $tmp is $len long. # Output AND information.
|
||||
}
|
||||
|
||||
# This is the short-named version.
|
||||
_pls() {
|
||||
local IFS=$'x1B' # \ESC character (not required)
|
||||
echo $'\x27'$@$'\x27' # Hard quoted parameter glob
|
||||
}
|
||||
|
||||
# :<<-'_Protect_Literal_String_Test'
|
||||
# # # Remove the above "# " to disable this code. # # #
|
||||
|
||||
# See how that looks when printed.
|
||||
echo
|
||||
echo "- - Test One - -"
|
||||
_protect_literal_str 'Hello $user'
|
||||
_protect_literal_str 'Hello "${username}"'
|
||||
echo
|
||||
|
||||
# Which yields:
|
||||
# - - Test One - -
|
||||
# 'Hello $user' is 13 long.
|
||||
# 'Hello "${username}"' is 21 long.
|
||||
|
||||
# Looks as expected, but why all of the trouble?
|
||||
# The difference is hidden inside the Bash internal order
|
||||
#+ of operations.
|
||||
# Which shows when you use it on the RHS of an assignment.
|
||||
|
||||
# Declare an array for test values.
|
||||
declare -a arrayZ
|
||||
|
||||
# Assign elements with various types of quotes and escapes.
|
||||
arrayZ=( zero "$(_pls 'Hello ${Me}')" 'Hello ${You}' "\'Pass: ${pw}\'" )
|
||||
|
||||
# Now list that array and see what is there.
|
||||
echo "- - Test Two - -"
|
||||
for (( i=0 ; i<${#arrayZ[*]} ; i++ ))
|
||||
do
|
||||
echo Element $i: ${arrayZ[$i]} is: ${#arrayZ[$i]} long.
|
||||
done
|
||||
echo
|
||||
|
||||
# Which yields:
|
||||
# - - Test Two - -
|
||||
# Element 0: zero is: 4 long. # Our marker element
|
||||
# Element 1: 'Hello ${Me}' is: 13 long. # Our "$(_pls '...' )"
|
||||
# Element 2: Hello ${You} is: 12 long. # Quotes are missing
|
||||
# Element 3: \'Pass: \' is: 10 long. # ${pw} expanded to nothing
|
||||
|
||||
# Now make an assignment with that result.
|
||||
declare -a array2=( ${arrayZ[@]} )
|
||||
|
||||
# And print what happened.
|
||||
echo "- - Test Three - -"
|
||||
for (( i=0 ; i<${#array2[*]} ; i++ ))
|
||||
do
|
||||
echo Element $i: ${array2[$i]} is: ${#array2[$i]} long.
|
||||
done
|
||||
echo
|
||||
|
||||
# Which yields:
|
||||
# - - Test Three - -
|
||||
# Element 0: zero is: 4 long. # Our marker element.
|
||||
# Element 1: Hello ${Me} is: 11 long. # Intended result.
|
||||
# Element 2: Hello is: 5 long. # ${You} expanded to nothing.
|
||||
# Element 3: 'Pass: is: 6 long. # Split on the whitespace.
|
||||
# Element 4: ' is: 1 long. # The end quote is here now.
|
||||
|
||||
# Our Element 1 has had its leading and trailing hard quotes stripped.
|
||||
# Although not shown, leading and trailing whitespace is also stripped.
|
||||
# Now that the string contents are set, Bash will always, internally,
|
||||
#+ hard quote the contents as required during its operations.
|
||||
|
||||
# Why?
|
||||
# Considering our "$(_pls 'Hello ${Me}')" construction:
|
||||
# " ... " -> Expansion required, strip the quotes.
|
||||
# $( ... ) -> Replace with the result of..., strip this.
|
||||
# _pls ' ... ' -> called with literal arguments, strip the quotes.
|
||||
# The result returned includes hard quotes; BUT the above processing
|
||||
#+ has already been done, so they become part of the value assigned.
|
||||
#
|
||||
# Similarly, during further usage of the string variable, the ${Me}
|
||||
#+ is part of the contents (result) and survives any operations
|
||||
# (Until explicitly told to evaluate the string).
|
||||
|
||||
# Hint: See what happens when the hard quotes ($'\x27') are replaced
|
||||
#+ with soft quotes ($'\x22') in the above procedures.
|
||||
# Interesting also is to remove the addition of any quoting.
|
||||
|
||||
# _Protect_Literal_String_Test
|
||||
# # # Remove the above "# " to disable this code. # # #
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,174 @@
|
|||
#!/bin/bash
|
||||
# random-between.sh
|
||||
# Random number between two specified values.
|
||||
# Script by Bill Gradwohl, with minor modifications by the document author.
|
||||
# Used with permission.
|
||||
|
||||
|
||||
randomBetween() {
|
||||
# Generates a positive or negative random number
|
||||
#+ between $min and $max
|
||||
#+ and divisible by $divisibleBy.
|
||||
# Gives a "reasonably random" distribution of return values.
|
||||
#
|
||||
# Bill Gradwohl - Oct 1, 2003
|
||||
|
||||
syntax() {
|
||||
# Function embedded within function.
|
||||
echo
|
||||
echo "Syntax: randomBetween [min] [max] [multiple]"
|
||||
echo
|
||||
echo "Expects up to 3 passed parameters, but all are completely optional."
|
||||
echo "min is the minimum value"
|
||||
echo "max is the maximum value"
|
||||
echo "multiple specifies that the answer must be a multiple of this value."
|
||||
echo " i.e. answer must be evenly divisible by this number."
|
||||
echo
|
||||
echo "If any value is missing, defaults area supplied as: 0 32767 1"
|
||||
echo "Successful completion returns 0, unsuccessful completion returns"
|
||||
echo "function syntax and 1."
|
||||
echo "The answer is returned in the global variable randomBetweenAnswer"
|
||||
echo "Negative values for any passed parameter are handled correctly."
|
||||
}
|
||||
|
||||
local min=${1:-0}
|
||||
local max=${2:-32767}
|
||||
local divisibleBy=${3:-1}
|
||||
# Default values assigned, in case parameters not passed to function.
|
||||
|
||||
local x
|
||||
local spread
|
||||
|
||||
# Let's make sure the divisibleBy value is positive.
|
||||
[ ${divisibleBy} -lt 0 ] && divisibleBy=$((0-divisibleBy))
|
||||
|
||||
# Sanity check.
|
||||
if [ $# -gt 3 -o ${divisibleBy} -eq 0 -o ${min} -eq ${max} ]; then
|
||||
syntax
|
||||
return 1
|
||||
fi
|
||||
|
||||
# See if the min and max are reversed.
|
||||
if [ ${min} -gt ${max} ]; then
|
||||
# Swap them.
|
||||
x=${min}
|
||||
min=${max}
|
||||
max=${x}
|
||||
fi
|
||||
|
||||
# If min is itself not evenly divisible by $divisibleBy,
|
||||
#+ then fix the min to be within range.
|
||||
if [ $((min/divisibleBy*divisibleBy)) -ne ${min} ]; then
|
||||
if [ ${min} -lt 0 ]; then
|
||||
min=$((min/divisibleBy*divisibleBy))
|
||||
else
|
||||
min=$((((min/divisibleBy)+1)*divisibleBy))
|
||||
fi
|
||||
fi
|
||||
|
||||
# If max is itself not evenly divisible by $divisibleBy,
|
||||
#+ then fix the max to be within range.
|
||||
if [ $((max/divisibleBy*divisibleBy)) -ne ${max} ]; then
|
||||
if [ ${max} -lt 0 ]; then
|
||||
max=$((((max/divisibleBy)-1)*divisibleBy))
|
||||
else
|
||||
max=$((max/divisibleBy*divisibleBy))
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Now do the real work.
|
||||
|
||||
# Note that to get a proper distribution for the end points, the
|
||||
#+ range of random values has to be allowed to go between 0 and
|
||||
#+ abs(max-min)+divisibleBy, not just abs(max-min)+1.
|
||||
|
||||
# The slight increase will produce the proper distribution for the
|
||||
#+ end points.
|
||||
|
||||
# Changing the formula to use abs(max-min)+1 will still produce
|
||||
#+ correct answers, but the randomness of those answers is faulty in
|
||||
#+ that the number of times the end points ($min and $max) are returned
|
||||
#+ is considerably lower than when the correct formula is used.
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
spread=$((max-min))
|
||||
[ ${spread} -lt 0 ] && spread=$((0-spread))
|
||||
let spread+=divisibleBy
|
||||
randomBetweenAnswer=$(((RANDOM%spread)/divisibleBy*divisibleBy+min))
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Let's test the function.
|
||||
min=-14
|
||||
max=20
|
||||
divisibleBy=3
|
||||
|
||||
|
||||
# Generate an array of expected answers and check to make sure we get
|
||||
#+ at least one of each answer if we loop long enough.
|
||||
|
||||
declare -a answer
|
||||
minimum=${min}
|
||||
maximum=${max}
|
||||
if [ $((minimum/divisibleBy*divisibleBy)) -ne ${minimum} ]; then
|
||||
if [ ${minimum} -lt 0 ]; then
|
||||
minimum=$((minimum/divisibleBy*divisibleBy))
|
||||
else
|
||||
minimum=$((((minimum/divisibleBy)+1)*divisibleBy))
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# If max is itself not evenly divisible by $divisibleBy,
|
||||
#+ then fix the max to be within range.
|
||||
|
||||
if [ $((maximum/divisibleBy*divisibleBy)) -ne ${maximum} ]; then
|
||||
if [ ${maximum} -lt 0 ]; then
|
||||
maximum=$((((maximum/divisibleBy)-1)*divisibleBy))
|
||||
else
|
||||
maximum=$((maximum/divisibleBy*divisibleBy))
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# We need to generate only positive array subscripts,
|
||||
#+ so we need a displacement that that will guarantee
|
||||
#+ positive results.
|
||||
|
||||
displacement=$((0-minimum))
|
||||
for ((i=${minimum}; i<=${maximum}; i+=divisibleBy)); do
|
||||
answer[i+displacement]=0
|
||||
done
|
||||
|
||||
|
||||
# Now loop a large number of times to see what we get.
|
||||
loopIt=1000 # The script author suggests 100000,
|
||||
#+ but that takes a good long while.
|
||||
|
||||
for ((i=0; i<${loopIt}; ++i)); do
|
||||
|
||||
# Note that we are specifying min and max in reversed order here to
|
||||
#+ make the function correct for this case.
|
||||
|
||||
randomBetween ${max} ${min} ${divisibleBy}
|
||||
|
||||
# Report an error if an answer is unexpected.
|
||||
[ ${randomBetweenAnswer} -lt ${min} -o ${randomBetweenAnswer} -gt ${max} ] && echo MIN or MAX error - ${randomBetweenAnswer}!
|
||||
[ $((randomBetweenAnswer%${divisibleBy})) -ne 0 ] && echo DIVISIBLE BY error - ${randomBetweenAnswer}!
|
||||
|
||||
# Store the answer away statistically.
|
||||
answer[randomBetweenAnswer+displacement]=$((answer[randomBetweenAnswer+displacement]+1))
|
||||
done
|
||||
|
||||
|
||||
|
||||
# Let's check the results
|
||||
|
||||
for ((i=${minimum}; i<=${maximum}; i+=divisibleBy)); do
|
||||
[ ${answer[i+displacement]} -eq 0 ] && echo "We never got an answer of $i." || echo "${i} occurred ${answer[i+displacement]} times."
|
||||
done
|
||||
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,35 @@
|
|||
#!/bin/sh
|
||||
# readpipe.sh
|
||||
# This example contributed by Bjon Eriksson.
|
||||
|
||||
last="(null)"
|
||||
cat $0 |
|
||||
while read line
|
||||
do
|
||||
echo "{$line}"
|
||||
last=$line
|
||||
done
|
||||
printf "\nAll done, last:$last\n"
|
||||
|
||||
exit 0 # End of code.
|
||||
# (Partial) output of script follows.
|
||||
# The 'echo' supplies extra brackets.
|
||||
|
||||
#############################################
|
||||
|
||||
./readpipe.sh
|
||||
|
||||
{#!/bin/sh}
|
||||
{last="(null)"}
|
||||
{cat $0 |}
|
||||
{while read line}
|
||||
{do}
|
||||
{echo "{$line}"}
|
||||
{last=$line}
|
||||
{done}
|
||||
{printf "nAll done, last:$lastn"}
|
||||
|
||||
|
||||
All done, last:(null)
|
||||
|
||||
The variable (last) is set within the subshell but unset outside.
|
|
@ -0,0 +1,123 @@
|
|||
#! /bin/bash
|
||||
# unprotect_literal.sh
|
||||
|
||||
# set -vx
|
||||
|
||||
:<<-'_UnProtect_Literal_String_Doc'
|
||||
|
||||
Copyright (c) Michael S. Zick, 2003; All Rights Reserved
|
||||
License: Unrestricted reuse in any form, for any purpose.
|
||||
Warranty: None
|
||||
Revision: $ID$
|
||||
|
||||
Documentation redirected to the Bash no-operation. Bash will
|
||||
'/dev/null' this block when the script is first read.
|
||||
(Uncomment the above set command to see this action.)
|
||||
|
||||
Remove the first (Sha-Bang) line when sourcing this as a library
|
||||
procedure. Also comment out the example use code in the two
|
||||
places where shown.
|
||||
|
||||
|
||||
Usage:
|
||||
Complement of the "$(_pls 'Literal String')" function.
|
||||
(See the protect_literal.sh example.)
|
||||
|
||||
StringVar=$(_upls ProtectedSringVariable)
|
||||
|
||||
Does:
|
||||
When used on the right-hand-side of an assignment statement;
|
||||
makes the substitions embedded in the protected string.
|
||||
|
||||
Notes:
|
||||
The strange names (_*) are used to avoid trampling on
|
||||
the user's chosen names when this is sourced as a
|
||||
library.
|
||||
|
||||
|
||||
_UnProtect_Literal_String_Doc
|
||||
|
||||
_upls() {
|
||||
local IFS=$'x1B' # \ESC character (not required)
|
||||
eval echo $@ # Substitution on the glob.
|
||||
}
|
||||
|
||||
# :<<-'_UnProtect_Literal_String_Test'
|
||||
# # # Remove the above "# " to disable this code. # # #
|
||||
|
||||
|
||||
_pls() {
|
||||
local IFS=$'x1B' # \ESC character (not required)
|
||||
echo $'\x27'$@$'\x27' # Hard quoted parameter glob
|
||||
}
|
||||
|
||||
# Declare an array for test values.
|
||||
declare -a arrayZ
|
||||
|
||||
# Assign elements with various types of quotes and escapes.
|
||||
arrayZ=( zero "$(_pls 'Hello ${Me}')" 'Hello ${You}' "\'Pass: ${pw}\'" )
|
||||
|
||||
# Now make an assignment with that result.
|
||||
declare -a array2=( ${arrayZ[@]} )
|
||||
|
||||
# Which yielded:
|
||||
# - - Test Three - -
|
||||
# Element 0: zero is: 4 long # Our marker element.
|
||||
# Element 1: Hello ${Me} is: 11 long # Intended result.
|
||||
# Element 2: Hello is: 5 long # ${You} expanded to nothing.
|
||||
# Element 3: 'Pass: is: 6 long # Split on the whitespace.
|
||||
# Element 4: ' is: 1 long # The end quote is here now.
|
||||
|
||||
# set -vx
|
||||
|
||||
# Initialize 'Me' to something for the embedded ${Me} substitution.
|
||||
# This needs to be done ONLY just prior to evaluating the
|
||||
#+ protected string.
|
||||
# (This is why it was protected to begin with.)
|
||||
|
||||
Me="to the array guy."
|
||||
|
||||
# Set a string variable destination to the result.
|
||||
newVar=$(_upls ${array2[1]})
|
||||
|
||||
# Show what the contents are.
|
||||
echo $newVar
|
||||
|
||||
# Do we really need a function to do this?
|
||||
newerVar=$(eval echo ${array2[1]})
|
||||
echo $newerVar
|
||||
|
||||
# I guess not, but the _upls function gives us a place to hang
|
||||
#+ the documentation on.
|
||||
# This helps when we forget what a # construction like:
|
||||
#+ $(eval echo ... ) means.
|
||||
|
||||
# What if Me isn't set when the protected string is evaluated?
|
||||
unset Me
|
||||
newestVar=$(_upls ${array2[1]})
|
||||
echo $newestVar
|
||||
|
||||
# Just gone, no hints, no runs, no errors.
|
||||
|
||||
# Why in the world?
|
||||
# Setting the contents of a string variable containing character
|
||||
#+ sequences that have a meaning to Bash is a general problem in
|
||||
#+ script programming.
|
||||
#
|
||||
# This problem is now solved in eight lines of code
|
||||
#+ (and four pages of description).
|
||||
|
||||
# Where is all this going?
|
||||
# Dynamic content Web pages as an array of Bash strings.
|
||||
# Content set per request by a Bash 'eval' command
|
||||
#+ on the stored page template.
|
||||
# Not intended to replace PHP, just an interesting thing to do.
|
||||
###
|
||||
# Don't have a webserver application?
|
||||
# No problem, check the example directory of the Bash source;
|
||||
#+ there is a Bash script for that also.
|
||||
|
||||
# _UnProtect_Literal_String_Test
|
||||
# # # Remove the above "# " to disable this code. # # #
|
||||
|
||||
exit 0
|
Loading…
Reference in New Issue