Many Linux administrators encounter this frustrating error when processing user data from CSV files:
./test.sh: line 5: UID: readonly variable
The script might work perfectly in development but fails in production environments. Let's examine why this happens and how to properly handle system-reserved variables.
The error occurs because UID
is a special shell variable in Unix/Linux systems. It's a readonly variable that stores the current user's numeric ID. When your script tries to reassign it, the shell prevents modification.
Here's the corrected version of the script with proper variable naming:
#!/bin/bash
while IFS= read -r inputline
do
user_id="$(echo "$inputline" | cut -d '\"' -f4)"
password="$(echo "$inputline" | cut -d '\"' -f8)"
first_name="$(echo "$inputline" | cut -d '\"' -f6 | cut -d ' ' -f1)"
last_name="$(echo "$inputline" | cut -d '\"' -f6 | cut -d ' ' -f2)"
zmprov createAccount "$user_id" "$password" displayName "$first_name $last_name" \
givenName "$first_name" sn "$last_name"
done < company.csv
- Changed
UID
touser_id
to avoid system variable conflict - Added
-r
toread
to preserve backslashes - Set
IFS=
to prevent leading/trailing whitespace trimming - Quoted all variable expansions to handle spaces/special characters
- Used
#!/bin/bash
shebang for more consistent behavior
For more robust CSV parsing, consider these approaches:
# Using awk for better field handling
user_id=$(awk -F'"' '{print $4}' <<< "$inputline")
# Using IFS for direct field splitting
IFS=\" read -r _ _ _ user_id _ _ _ password _ first_last _ <<< "$inputline"
You can list all read-only shell variables with:
readonly -p | grep -E '^declare -r'
Common reserved variables to avoid include: UID
, EUID
, PPID
, SHELLOPTS
, and BASH_VERSINFO
.
When migrating scripts between environments:
- Test with
bash -n script.sh
for syntax errors - Run
shellcheck script.sh
for common pitfalls - Consider using environment-specific variable prefixes
- Implement proper error handling and logging
When working with bash scripts that handle user account creation or data processing, you might encounter the frustrating "readonly variable" error for UID. This typically occurs when:
- Running scripts across different Linux environments
- Processing CSV files containing user information
- Attempting to modify system-reserved variables
The error occurs because UID
is a special shell variable in Unix-like systems (declared readonly in POSIX) that stores the current user's numeric ID. When your script tries to assign a new value to it, the shell prevents modification.
# Try this in your terminal:
echo $UID # Shows your current user ID
UID=1001 # Will produce "UID: readonly variable"
Here are three robust approaches to handle this:
# Option 1: Use a different variable name (recommended)
user_id="$(echo $inputline | cut -d '\"' -f4)"
# Option 2: Use lowercase (convention for script variables)
uid="$(echo $inputline | cut -d '\"' -f4)"
# Option 3: For Zimbra-specific scripts (zmprov), consider:
account_id="$(echo $inputline | cut -d '\"' -f4)"
Here's a more robust version of your original script with better practices:
#!/bin/bash
while IFS= read -r inputline
do
user_id="$(echo "$inputline" | cut -d '\"' -f4)"
password="$(echo "$inputline" | cut -d '\"' -f8)"
first_name="$(echo "$inputline" | cut -d '\"' -f6 | cut -d ' ' -f1)"
last_name="$(echo "$inputline" | cut -d '\"' -f6 | cut -d ' ' -f2)"
zmprov createAccount "$user_id" "$password" \
displayName "$first_name $last_name" \
givenName "$first_name" \
sn "$last_name"
done < company.csv
- Use
#!/bin/bash
instead of#!/bin/sh
for better compatibility - Always quote variables to handle spaces in CSV fields
- Add error handling for CSV parsing
- Consider using
awk
for more complex CSV processing
Before running against production, test with:
# Dry-run mode
while IFS= read -r line; do
user_id="$(echo "$line" | cut -d '\"' -f4)"
echo "Would create account for: $user_id"
done < company.csv