Skip to content

Instantly share code, notes, and snippets.

@loopyd
Last active November 14, 2023 04:35
Show Gist options
  • Save loopyd/5161b606188280d955975edbc2785779 to your computer and use it in GitHub Desktop.
Save loopyd/5161b606188280d955975edbc2785779 to your computer and use it in GitHub Desktop.
[Bash] ini parselib - Bash/perl library for reading/modifying ini files
#!/bin/bash
#
# 📯 * AAAAAAAAAAAAAAAAAAAUUUUUUUUUUUUUUUUHHHHHHNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN!!!! * 📯
#
# You didn't ask. I did it anyway. Now as a zero-dependency gulp.sh
#
# CONTRIBUTIONS? BUGFIXES? UNCONVERED EDGE CASES? Make them known.
#
# update_ini_file: Updates or adds a key-value pair in a specific section of an INI file
# Arguments:
# file: The INI file to update
# section: The section in the INI file where the key-value pair resides
# key: The key to update/add
# raw_value: The value to be assigned to the key
# comment: Optional comment to be added above the section
update_ini_file() {
local file=$1 section=$2 key=$3 raw_value=$4 comment=${5:-} append=${6:-false}
[ ! -f "$file" ] && { echo "File not found: $file"; return 1; }
local formatted_value=$(perl -e 'use strict; use warnings; my ($value, $append) = @ARGV;
my @elements = split(/[;,]/, $value); for my $el (@elements) { if ($el =~ /^[.\/~]?[-a-zA-Z0-9_\/\\]+(\.[a-zA-Z0-9]+)?$/) {
$el =~ s/ /\\ /g; } elsif ($el =~ /^(true|false)$/i) { $el = lc $el; } elsif ($el =~ /^[+-]?[0-9]+\.[0-9]+$/) {
$el = "\"$el\""; } elsif ($el =~ /^[0-9]+(\.[0-9]+)?[KMGTEP]B$/i) { $el = uc $el; } elsif ($el !~ /^[+-]?[0-9]+$/) {
$el = "\"$el\""; } } $value = join(",", @elements); if ($append eq "true") { open my $fh, "<", $ARGV[2]
or die "Could not open file: $!"; my $content = do { local $/; <$fh> }; close $fh; if ($content =~ /\['"$section"'\].*^\s*'"$key"'=([^\n]*)/ms) {
my $existing_value = $1; $value = $existing_value . "," . $value unless $existing_value =~ /\Q$value\E/; }
print $value;' "$raw_value" "$append" "$file")
perl -i -pe 'BEGIN {$/ = "";} s/\r\n/\n/g; s/[^\x00-\x7F]//g; s/^\s+|\s+$//g;
s/^(#|;).*?\n//mg if $. == 1; s/^\['"$section"'\]\K(.*?)(\n\n|\Z)/$1 =~ s/^\s*'"$key"'=.*\n//rm . "'"$key"'='"$formatted_value"'\n"/es;' "$file"
[ -n "$comment" ] && perl -i -pe 's/(?<=\n)^\['"$section"'\]/\n# '"$comment"'\n\['"$section"'\]/' "$file"
perl -i -pe 's/(?<!\n\n)\n\[/\n\n\[/g' "$file"
}
# fetch_ini_file: Retrieves the value of a specific key from a specific section of an INI file
# Arguments:
# file: The INI file to read
# section: The section in the INI file
# key: The key whose value is to be retrieved
fetch_ini_file() {
local file=$1 section=$2 key=$3
[ ! -f "$file" ] && { echo "File not found: $file"; return 1; }
local value=$(perl -ne 'my $section_found = 0; if (/^\['"$section"'\]/) { $section_found = 1; }
if ($section_found && /^\s*'"$key"'=([^#\n;]+)/) { print "$1\n"; exit; }
$section_found = 0 if /^\[/ && !/^\['"$section"'\]/;' "$file")
if [[ $value =~ , ]]; then IFS=',' read -r -a array <<< "$value"; echo "${array[@]}"; else echo "$value"; fi
}
# test_ini_file: Test case for the INI file parselib
# Arguments:
# file: The INI file to generate
test_ini_file() {
local file=$1
local max_sections=$((RANDOM % 5 + 1))
local max_keys=$((RANDOM % 5 + 1))
local sections=()
for ((section = 1; section <= max_sections; section++)); do
local section_name="section$section"
sections+=("$section_name")
for ((key = 1; key <= max_keys; key++)); do
local key_name="key$key"
local update_or_add=$((RANDOM % 2))
local value_type=$((RANDOM % 7))
case $value_type in
0)
local value="\"String$(date +%N)\""
;;
1)
local value=$((RANDOM % 100))
;;
2)
local value="$(echo "scale=2; $RANDOM/100" | bc)"
;;
3)
local value="true"
;;
4)
local value="\"Path/to/file$(date +%N).txt\""
;;
5)
local array_size=$((RANDOM % 4 + 2))
local value=""
for ((i = 0; i < array_size; i++)); do
local array_element_type=$((RANDOM % 6))
local array_element
case $array_element_type in
0)
array_element="\"String$(date +%N)\""
;;
1)
array_element=$((RANDOM % 100))
;;
2)
array_element="$(echo "scale=2; $RANDOM/100" | bc)"
;;
3)
array_element=$([ $((RANDOM % 2)) == 1 ] && echo "true" || echo "false")
;;
4)
array_element="\"Path$(date +%N).txt\""
;;
5)
array_element="${RANDOM}$(echo "KB MB GB TB" | tr ' ' '\n' | shuf -n 1)"
;;
*)
array_element="\"String$(date +%N)\""
;;
esac
value+="$array_element"
if ((i < array_size - 1)); then
value+=","
fi
done
;;
6)
local value="${RANDOM}$(echo "KB MB GB TB" | tr ' ' '\n' | shuf -n 1)"
;;
esac
if [[ $update_or_add -eq 0 && ${#sections[@]} -gt 0 ]]; then
local random_section="${sections[$RANDOM % ${#sections[@]}]}"
update_ini_file "$file" "$random_section" "$key_name" "$value"
else
update_ini_file "$file" "$section_name" "$key_name" "$value"
fi
local fetched_value=$(fetch_ini_file "$file" "$section_name" "$key_name")
echo "Fetched Value: $fetched_value"
done
done
}
test_ini_file "test.ini"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment