When building automation scripts that require user input, properly capturing multi-line text with special characters (like backspace) can be tricky. Here's a robust solution that works across Unix-like systems including macOS.
#!/bin/bash
echo "Enter version notes (press Ctrl+D when done):"
versionNotes=$(cat)
echo "Captured input:"
printf "%s\n" "$versionNotes"
The cat
command reads until EOF (Ctrl+D) and properly handles:
- Backspace and other control characters
- Arbitrary line lengths
- Special characters in the input
For cases where you want an explicit end marker:
read -r -d 'END' versionNotes <<'EOF'
first line
second line with special chars !@#
third line
END
For your specific use case of writing to application.yml:
{
echo "version_notes: |"
sed 's/^/ /' <<< "$versionNotes"
} >> source/application.yml
1. Leading/trailing whitespace preservation:
versionNotes=$(cat; echo x)
versionNotes=${versionNotes%x}
2. Handling tabs and special indentation:
Use IFS=
to prevent trimming
When building automation scripts on macOS (including legacy 10.6.8 systems), properly capturing multi-line user input can be surprisingly tricky. Let's explore several robust approaches with their trade-offs.
This method uses a delimiter to mark input termination:
read -r -d '' versionNotes <<'END'
# User pastes/pastes multi-line content here
# Supports backspacing normally
END
Key advantages:
- Preserves all formatting including indentation
- Handles special characters correctly
- Allows normal text editing during input
For complex input scenarios, spawning a temporary editor works best:
#!/bin/bash
tempfile=$(mktemp)
${EDITOR:-nano} "$tempfile"
versionNotes=$(<"$tempfile")
rm "$tempfile"
# Append to config
echo "version_notes: |" >> source/application.yml
awk '{print " "$0}' <<< "$versionNotes" >> source/application.yml
A more controlled approach for line-by-line processing:
echo "Enter version notes (empty line to finish):"
while IFS= read -r line; do
[[ $line ]] || break
versionNotes+="$line"$'\n'
done
printf "Captured notes:\n%s" "$versionNotes"
For backward compatibility with older Bash versions (pre-4.0):
{
echo "version_notes: |"
while IFS= read -r line; do
echo " $line"
done
} > source/application.yml
Common pitfalls to avoid:
- Always use
-r
with read to prevent backslash interpretation - Set
IFS=
to preserve leading/trailing whitespace - Use
$'\n'
for explicit newlines in variable concatenation