Keywords: Shell scripting | Properties file parsing | Character substitution | eval command | Bourne shell limitations
Abstract: This paper provides an in-depth exploration of the technical challenges and solutions for parsing .properties files containing period characters (.) in Shell scripts. By analyzing Bourne shell variable naming restrictions, it details the core methodology of using tr command for character substitution and eval command for variable assignment. The article also discusses extended techniques for handling complex character formats, compares the advantages and disadvantages of different parsing approaches, and offers practical code examples and best practice guidance for developers.
Technical Background and Problem Analysis
In Shell script development, .properties files are common configuration file formats used to store application parameters. However, when key names in these files contain period characters (.), direct parsing using Shell's source command or dot operator (.) encounters fundamental obstacles. This is because Bourne shell and its derivatives (such as bash, sh) have strict variable naming conventions that prohibit period characters—variable names can only contain letters, numbers, and underscores, and cannot start with a number.
Consider the following typical .properties file example:
# app.properties
db.uat.user=sample user
db.uat.passwd=secret
If attempting to use the traditional source command:
#!/bin/sh
file="./app.properties"
if [ -f "$file" ]; then
. $file
echo "User Id: $db.uat.user"
echo "Password: $db.uat.passwd"
fi
This code will fail because Shell interprets db.uat.user as three separate tokens rather than a complete variable name. Worse, when values contain spaces (like "sample user"), parsing becomes further complicated as Shell uses spaces as field separators by default.
Core Solution: Character Substitution and Dynamic Evaluation
The core approach to solving this problem involves substituting period characters with Shell-allowed characters (such as underscores) using the tr command, then dynamically creating variables with the eval command. Below is optimized and thoroughly commented implementation code:
#!/bin/sh
# Define configuration file path
file="./app.properties"
# Check if file exists
if [ -f "$file" ]; then
echo "Configuration file $file found, starting parsing..."
# Use while loop to read file line by line
while IFS='=' read -r key value
do
# Skip empty lines and comment lines (starting with #)
if [[ -z "$key" || "$key" =~ ^# ]]; then
continue
fi
# Replace period characters in key names with underscores
# tr command performs character-to-character translation
safe_key=$(echo "$key" | tr '.' '_')
# Use eval to dynamically create variable
# Note: Value is wrapped in quotes to properly handle spaces
eval "${safe_key}='${value}'"
# Debug output: show conversion process
echo "Parsing: $key -> $safe_key = '$value'"
done < "$file"
# Access parsed variables
echo "\nParsing results:"
echo "User ID: ${db_uat_user}"
echo "User Password: ${db_uat_passwd}"
else
echo "Error: Configuration file $file not found"
exit 1
fi
In-depth Technical Analysis
1. IFS and read Command Collaboration
IFS='=' sets the field separator to equals sign, enabling read -r key value to correctly split each line into key and value parts. The -r option prevents backslashes from being interpreted as escape characters, which is crucial for values containing special characters.
2. tr Command Character Conversion Mechanism
tr '.' '_' performs simple character-to-character mapping, replacing all period characters with underscores. This conversion is necessary because:
- Shell variable names cannot contain period characters
- Underscores are valid characters in Shell variable names
- The conversion maintains key name readability and uniqueness
3. Safe Usage of eval Command
The eval command executes a string as a Shell command, enabling dynamic variable creation. However, it must be used cautiously:
# Safe approach: wrap value in quotes
eval "${safe_key}='${value}'"
# Dangerous approach: direct concatenation, may execute malicious code
eval "${safe_key}=${value}"
By wrapping ${value} in single quotes, we ensure that even if values contain Shell special characters (like $, `, \), they won't be accidentally interpreted.
Handling Complex Character Formats
For .properties files containing more special characters, more complex conversion logic may be required. For example, Ant property files might contain various special characters:
# Extended character conversion example
key=$(echo "$key" | tr .-/ _ | tr -cd 'A-Za-z0-9_')
# Breakdown explanation:
# 1. tr .-/ _ : Convert periods, slashes, and hyphens to underscores
# 2. tr -cd 'A-Za-z0-9_' : Delete all non-alphanumeric and non-underscore characters
# -c : Complement (delete specified character set)
# -d : Delete operation
This conversion ensures generated variable names fully comply with Shell naming conventions but may alter the original key name semantics. In practical applications, balance must be found between preserving semantics and ensuring compatibility.
Alternative Method Comparison
grep-based Method (Reference Answer 1)
function prop {
grep "^${1}" env/${ENV}.properties | cut -d'=' -f2
}
# Usage example
echo "Database user: $(prop 'app.database.user')"
Advantages:
- Simple implementation, no character conversion needed
- Avoids eval usage, higher security
- Suitable for read-only access scenarios
Disadvantages:
- Requires file parsing for each access, poor performance
- Not suitable for scenarios requiring multiple accesses or variable modifications
- Cannot directly use Shell variable expansion features
AWK-based Method
#!/bin/bash
# Parse and set variables using AWK
while IFS='=' read -r key value; do
if [[ ! "$key" =~ ^# ]]; then
export "${key//./_}=$value"
fi
done < <(awk -F= '!/^#/ && NF==2 {print $1"="$2}' app.properties)
# Or more concise AWK version
eval $(awk -F= '!/^#/ && NF==2 {gsub(\".\", \"_\", $1); print $1"='"$2"'"}' app.properties)
Advantages:
- AWK provides more powerful text processing capabilities
- Can handle more complex file formats
- Single-line command implementation, concise code
Disadvantages:
- AWK syntax relatively complex
- Slightly poorer portability (depends on AWK version)
- Higher debugging and maintenance costs
Best Practice Recommendations
- Input Validation: Always validate configuration file integrity and format correctness
- Error Handling: Add appropriate error handling mechanisms for file non-existence, permission issues, etc.
- Performance Considerations: For large configuration files, consider caching parsing results
- Security: Avoid loading configuration files from untrusted sources, or strictly filter content
- Compatibility: Consider cross-Shell version compatibility (bash, sh, dash)
- Logging: Add detailed parsing logs in production environments for easier debugging
Practical Application Scenarios
This technique is particularly suitable for:
- Environment configuration in CI/CD pipelines
- Startup scripts for containerized applications (like Docker)
- Multi-environment (development, testing, production) configuration management
- Legacy system maintenance where .properties file format is fixed
Through the techniques introduced in this paper, developers can reliably parse .properties files containing period characters in Shell scripts while maintaining code robustness and maintainability. The choice of method depends on specific application requirements, performance needs, and security considerations.