Initial commit.
This commit is contained in:
commit
2dda2e227d
52 changed files with 2704 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
*~
|
||||||
|
*.save
|
||||||
|
.*.swp
|
||||||
12
SPEC
Normal file
12
SPEC
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
Blank lines are ignored.
|
||||||
|
Lines starting with # and ; (configurable; after leading whitespace removal) are treated as comments.
|
||||||
|
- Comments must appear on their own line.
|
||||||
|
Values can optionally be bookmarked with single or double quotes.
|
||||||
|
- If quotes are to be used, they must be the first and last characters of the value
|
||||||
|
- Occurances of the bookending quotes to be used within the value must be \ escaped. ???
|
||||||
|
- Whitespace within the quotes is retained verbatim.
|
||||||
|
- Backslash line continuation is supported within quotes (but leading whitespace on subsequent lines is removed).
|
||||||
|
Values can be continued by use of \ in the last column.
|
||||||
|
- Subsequent lines are subject to leading whitespace removal as normal.
|
||||||
|
- Comments are not recognised on subsequent lines - they are treated as part of the value.
|
||||||
|
Escaping of shell special characters is not required. ???
|
||||||
13
TODO
Normal file
13
TODO
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
-s <list>, --section=<list>Only parse the specified section(s). List multiple
|
||||||
|
sections seperated by commas. For the global section
|
||||||
|
use '.'. For every section except global, use '*'.
|
||||||
|
For every section including the global section, don't
|
||||||
|
use this option (or use '.,*').
|
||||||
|
|
||||||
|
--ignore-errors Ignore parse errors in the ini file and continue
|
||||||
|
processing. This will cause options to be ignored
|
||||||
|
and whole sections to be skipped if errors are found.
|
||||||
|
This option should not be used except for debugging.
|
||||||
|
|
||||||
|
|
||||||
|
Have the parser accept a filename of '-' to indicate it should read from stdin.
|
||||||
42
bits/comments.ini
Normal file
42
bits/comments.ini
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
# comment 1
|
||||||
|
; comment 2
|
||||||
|
# comment 3
|
||||||
|
; comment 4
|
||||||
|
# comment 5
|
||||||
|
; comment 6
|
||||||
|
# comment 7
|
||||||
|
; comment 8
|
||||||
|
# comment 9
|
||||||
|
; comment 10
|
||||||
|
# comment 11
|
||||||
|
; comment 12
|
||||||
|
# comment 13
|
||||||
|
; comment 14
|
||||||
|
#comment 15
|
||||||
|
;comment 16
|
||||||
|
##### comment 17
|
||||||
|
;;;;;;;; comment 18
|
||||||
|
########## comment 19
|
||||||
|
;;;; comment 20
|
||||||
|
# comment 21
|
||||||
|
;comment 22
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# comment 23 #
|
||||||
|
# # comment 24
|
||||||
|
# # comment 25
|
||||||
|
Valid 1
|
||||||
|
[header1]
|
||||||
|
Valid 2
|
||||||
|
Valid 3
|
||||||
|
Valid 4
|
||||||
|
[ header 2 ]
|
||||||
|
Valid 5
|
||||||
|
[ header 3 ]
|
||||||
|
[header_____4____]
|
||||||
|
[ $%"%^ ]
|
||||||
10
bits/duplicate-sections.ini
Normal file
10
bits/duplicate-sections.ini
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
global key 1 = value 1
|
||||||
|
|
||||||
|
[ section 1 ]
|
||||||
|
key 1 = value 1
|
||||||
|
|
||||||
|
[ section 2 ]
|
||||||
|
key 1 = value 1
|
||||||
|
|
||||||
|
[ section 1 ]
|
||||||
|
key 2 = value 2
|
||||||
314
bits/key-blanks.ini
Normal file
314
bits/key-blanks.ini
Normal file
|
|
@ -0,0 +1,314 @@
|
||||||
|
#######################################################
|
||||||
|
# Key format tests: = as deliminator #
|
||||||
|
# Blanks at the start of, in, and after each key name #
|
||||||
|
#######################################################
|
||||||
|
|
||||||
|
# Blanks in keys.
|
||||||
|
[blanks]
|
||||||
|
keyformattest1a= No blanks in key name, no blanks before or after key name
|
||||||
|
key formattest1b= Single space in key name, no blanks before or after key name
|
||||||
|
key format test 1c= Multiple spaces in key name, no blanks before or after key name
|
||||||
|
key format test 1d= Multiple consecutive spaces in key name, no blanks before or after key name
|
||||||
|
key formattest1e= Single tab in key name, no blanks before or after key name
|
||||||
|
key format test 1f= Multiple tabs in key name, no blanks before or after key name
|
||||||
|
key format test 1g= Multiple consecutive tabs in key name, no blanks before or after key name
|
||||||
|
|
||||||
|
# Blanks before keys.
|
||||||
|
[single space before key name]
|
||||||
|
keyformattest2a= No blanks in key name
|
||||||
|
key formattest2b= Single space in key name
|
||||||
|
key format test 2c= Multiple spaces in key name
|
||||||
|
key format test 2d= Multiple consecutive spaces in key name
|
||||||
|
key formattest2e= Single tab in key name
|
||||||
|
key format test 2f= Multiple tabs in key name
|
||||||
|
key format test 2g= Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[multiple spaces before key name]
|
||||||
|
keyformattest3a= No blanks in key name
|
||||||
|
key formattest3b= Single space in key name
|
||||||
|
key format test 3c= Multiple spaces in key name
|
||||||
|
key format test 3d= Multiple consecutive spaces in key name
|
||||||
|
key formattest3e= Single tab in key name
|
||||||
|
key format test 3f= Multiple tabs in key name
|
||||||
|
key format test 3g= Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[single tab before key name]
|
||||||
|
keyformattest4a= No blanks in key name
|
||||||
|
key formattest4b= Single space in key name
|
||||||
|
key format test 4c= Multiple spaces in key name
|
||||||
|
key format test 4d= Multiple consecutive spaces in key name
|
||||||
|
key formattest4e= Single tab in key name
|
||||||
|
key format test 4f= Multiple tabs in key name
|
||||||
|
key format test 4g= Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[multiple tabs before key name]
|
||||||
|
keyformattest5a= No blanks in key name
|
||||||
|
key formattest5b= Single space in key name
|
||||||
|
key format test 5c= Multiple spaces in key name
|
||||||
|
key format test 5d= Multiple consecutive spaces in key name
|
||||||
|
key formattest5e= Single tab in key name
|
||||||
|
key format test 5f= Multiple tabs in key name
|
||||||
|
key format test 5g= Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[single space after key name]
|
||||||
|
keyformattest6a = No blanks in key name
|
||||||
|
key formattest6b = Single space in key name
|
||||||
|
key format test 6c = Multiple spaces in key name
|
||||||
|
key format test 6d = Multiple consecutive spaces in key name
|
||||||
|
key formattest6e = Single tab in key name
|
||||||
|
key format test 6f = Multiple tabs in key name
|
||||||
|
key format test 6g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[multiple spaces after key name]
|
||||||
|
keyformattest7a = No blanks in key name
|
||||||
|
key formattest7b = Single space in key name
|
||||||
|
key format test 7c = Multiple spaces in key name
|
||||||
|
key format test 7d = Multiple consecutive spaces in key name
|
||||||
|
key formattest7e = Single tab in key name
|
||||||
|
key format test 7f = Multiple tabs in key name
|
||||||
|
key format test 7g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[single tab after key name]
|
||||||
|
keyformattest8a = No blanks in key name
|
||||||
|
key formattest8b = Single space in key name
|
||||||
|
key format test 8c = Multiple spaces in key name
|
||||||
|
key format test 8d = Multiple consecutive spaces in key name
|
||||||
|
key formattest8e = Single tab in key name
|
||||||
|
key format test 8f = Multiple tabs in key name
|
||||||
|
key format test 8g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[multiple tabs after key name]
|
||||||
|
keyformattest9a = No blanks in key name
|
||||||
|
key formattest9b = Single space in key name
|
||||||
|
key format test 9c= Multiple spaces in key name
|
||||||
|
key format test 9d = Multiple consecutive spaces in key name
|
||||||
|
key formattest9e = Single tab in key name
|
||||||
|
key format test 9f = Multiple tabs in key name
|
||||||
|
key format test 9g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[single space before and single space after key name]
|
||||||
|
keyformattest10a = No blanks in key name
|
||||||
|
key formattest10b = Single space in key name
|
||||||
|
key format test 10c = Multiple spaces in key name
|
||||||
|
key format test 10d = Multiple consecutive spaces in key name
|
||||||
|
key formattest10e = Single tab in key name
|
||||||
|
key format test 10f = Multiple tabs in key name
|
||||||
|
key format test 10g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[multiple spaces before and single space after key name]
|
||||||
|
keyformattest11a = No blanks in key name
|
||||||
|
key formattest11b = Single space in key name
|
||||||
|
key format test 11c = Multiple spaces in key name
|
||||||
|
key format test 11d = Multiple consecutive spaces in key name
|
||||||
|
key formattest11e = Single tab in key name
|
||||||
|
key format test 11f = Multiple tabs in key name
|
||||||
|
key format test 11g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[single tab before and single space after key name]
|
||||||
|
keyformattest12a = No blanks in key name
|
||||||
|
key formattest12b = Single space in key name
|
||||||
|
key format test 12c = Multiple spaces in key name
|
||||||
|
key format test 12d = Multiple consecutive spaces in key name
|
||||||
|
key formattest12e = Single tab in key name
|
||||||
|
key format test 12f = Multiple tabs in key name
|
||||||
|
key format test 12g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[multiple tabs before and single space after key name]
|
||||||
|
keyformattest13a = No blanks in key name
|
||||||
|
key formattest13b = Single space in key name
|
||||||
|
key format test 13c = Multiple spaces in key name
|
||||||
|
key format test 13d = Multiple consecutive spaces in key name
|
||||||
|
key formattest13e = Single tab in key name
|
||||||
|
key format test 13f = Multiple tabs in key name
|
||||||
|
key format test 13g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[single space before and multiple spaces after key name]
|
||||||
|
keyformattest14a = No blanks in key name
|
||||||
|
key formattest14b = Single space in key name
|
||||||
|
key format test 14c = Multiple spaces in key name
|
||||||
|
key format test 14d = Multiple consecutive spaces in key name
|
||||||
|
key formattest14e = Single tab in key name
|
||||||
|
key format test 14f = Multiple tabs in key name
|
||||||
|
key format test 14g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[multiple spaces before and multiple spaces after key name]
|
||||||
|
keyformattest15a = No blanks in key name
|
||||||
|
key formattest15b = Single space in key name
|
||||||
|
key format test 15c = Multiple spaces in key name
|
||||||
|
key format test 15d = Multiple consecutive spaces in key name
|
||||||
|
key formattest15e = Single tab in key name
|
||||||
|
key format test 15f = Multiple tabs in key name
|
||||||
|
key format test 15g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[single tab before and multiple spaces after key name]
|
||||||
|
keyformattest16a = No blanks in key name
|
||||||
|
key formattest16b = Single space in key name
|
||||||
|
key format test 16c = Multiple spaces in key name
|
||||||
|
key format test 16d = Multiple consecutive spaces in key name
|
||||||
|
key formattest16e = Single tab in key name
|
||||||
|
key format test 16f = Multiple tabs in key name
|
||||||
|
key format test 16g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[multiple tabs before and multiple spaces after key name]
|
||||||
|
keyformattest17a = No blanks in key name
|
||||||
|
key formattest17b = Single space in key name
|
||||||
|
key format test 17c = Multiple spaces in key name
|
||||||
|
key format test 17d = Multiple consecutive spaces in key name
|
||||||
|
key formattest17e = Single tab in key name
|
||||||
|
key format test 17f = Multiple tabs in key name
|
||||||
|
key format test 17g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[single space before and single tab after key name]
|
||||||
|
keyformattest18a = No blanks in key name
|
||||||
|
key formattest18b = Single space in key name
|
||||||
|
key format test 18c = Multiple spaces in key name
|
||||||
|
key format test 18d = Multiple consecutive spaces in key name
|
||||||
|
key formattest18e = Single tab in key name
|
||||||
|
key format test 18f = Multiple tabs in key name
|
||||||
|
key format test 18g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[multiple spaces before and single tab after key name]
|
||||||
|
keyformattest19a = No blanks in key name
|
||||||
|
key formattest19b = Single space in key name
|
||||||
|
key format test 19c = Multiple spaces in key name
|
||||||
|
key format test 19d = Multiple consecutive spaces in key name
|
||||||
|
key formattest19e = Single tab in key name
|
||||||
|
key format test 19f = Multiple tabs in key name
|
||||||
|
key format test 19g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[single tab before and single tab after key name]
|
||||||
|
keyformattest20a = No blanks in key name
|
||||||
|
key formattest20b = Single space in key name
|
||||||
|
key format test 20c = Multiple spaces in key name
|
||||||
|
key format test 20d = Multiple consecutive spaces in key name
|
||||||
|
key formattest20e = Single tab in key name
|
||||||
|
key format test 20f = Multiple tabs in key name
|
||||||
|
key format test 20g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[multiple tabs before and single tab after key name]
|
||||||
|
keyformattest21a = No blanks in key name
|
||||||
|
key formattest21b = Single space in key name
|
||||||
|
key format test 21c = Multiple spaces in key name
|
||||||
|
key format test 21d = Multiple consecutive spaces in key name
|
||||||
|
key formattest21e = Single tab in key name
|
||||||
|
key format test 21f = Multiple tabs in key name
|
||||||
|
key format test 21g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[single space before and multiple tabs after key name]
|
||||||
|
keyformattest22a = No blanks in key name
|
||||||
|
key formattest22b = Single space in key name
|
||||||
|
key format test 22c = Multiple spaces in key name
|
||||||
|
key format test 22d = Multiple consecutive spaces in key name
|
||||||
|
key formattest22e = Single tab in key name
|
||||||
|
key format test 22f = Multiple tabs in key name
|
||||||
|
key format test 22g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[multiple spaces before and multiple tabs after key name]
|
||||||
|
keyformattest23a = No blanks in key name
|
||||||
|
key formattest23b = Single space in key name
|
||||||
|
key format test 23c = Multiple spaces in key name
|
||||||
|
key format test 23d = Multiple consecutive spaces in key name
|
||||||
|
key formattest23e = Single tab in key name
|
||||||
|
key format test 23f = Multiple tabs in key name
|
||||||
|
key format test 23g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[single tab before and miltiple tabs after key name]
|
||||||
|
keyformattest24a = No blanks in key name
|
||||||
|
key formattest24b = Single space in key name
|
||||||
|
key format test 24c = Multiple spaces in key name
|
||||||
|
key format test 24d = Multiple consecutive spaces in key name
|
||||||
|
key formattest24e = Single tab in key name
|
||||||
|
key format test 24f = Multiple tabs in key name
|
||||||
|
key format test 24g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[multiple tabs before and multiple tabs after key name]
|
||||||
|
keyformattest25a = No blanks in key name
|
||||||
|
key formattest25b = Single space in key name
|
||||||
|
key format test 25c = Multiple spaces in key name
|
||||||
|
key format test 25d = Multiple consecutive spaces in key name
|
||||||
|
key formattest25e = Single tab in key name
|
||||||
|
key format test 25f = Multiple tabs in key name
|
||||||
|
key format test 25g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
|
||||||
|
[random mixture blanks before and single space after key name]
|
||||||
|
keyformattest26a = No blanks in key name
|
||||||
|
key formattest26b = Single space in key name
|
||||||
|
key format test 26c = Multiple spaces in key name
|
||||||
|
key format test 26d = Multiple consecutive spaces in key name
|
||||||
|
key formattest26e = Single tab in key name
|
||||||
|
key format test 26f = Multiple tabs in key name
|
||||||
|
key format test 26g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[random mixture blanks before and multiple spaces after key name]
|
||||||
|
keyformattest27a = No blanks in key name
|
||||||
|
key formattest27b = Single space in key name
|
||||||
|
key format test 27c = Multiple spaces in key name
|
||||||
|
key format test 27d = Multiple consecutive spaces in key name
|
||||||
|
key formattest27e = Single tab in key name
|
||||||
|
key format test 27f = Multiple tabs in key name
|
||||||
|
key format test 27g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[random mixture blanks before and single tab after key name]
|
||||||
|
keyformattest28a = No blanks in key name
|
||||||
|
key formattest28b = Single space in key name
|
||||||
|
key format test 28c = Multiple spaces in key name
|
||||||
|
key format test 28d = Multiple consecutive spaces in key name
|
||||||
|
key formattest28e = Single tab in key name
|
||||||
|
key format test 28f = Multiple tabs in key name
|
||||||
|
key format test 28g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[random mixture blanks before and multiple tabs after key name]
|
||||||
|
keyformattest29a = No blanks in key name
|
||||||
|
key formattest29b = Single space in key name
|
||||||
|
key format test 29c = Multiple spaces in key name
|
||||||
|
key format test 29d = Multiple consecutive spaces in key name
|
||||||
|
key formattest29e = Single tab in key name
|
||||||
|
key format test 29f = Multiple tabs in key name
|
||||||
|
key format test 29g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
|
||||||
|
[single space before and random mixture blanks after key name]
|
||||||
|
keyformattest30a = No blanks in key name
|
||||||
|
key formattest30b = Single space in key name
|
||||||
|
key format test 30c = Multiple spaces in key name
|
||||||
|
key format test 30d = Multiple consecutive spaces in key name
|
||||||
|
key formattest30e = Single tab in key name
|
||||||
|
key format test 30f = Multiple tabs in key name
|
||||||
|
key format test 30g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[multiple spaces before and random mixture blanks after key name]
|
||||||
|
keyformattest31a = No blanks in key name
|
||||||
|
key formattest31b = Single space in key name
|
||||||
|
key format test 31c = Multiple spaces in key name
|
||||||
|
key format test 31d = Multiple consecutive spaces in key name
|
||||||
|
key formattest31e = Single tab in key name
|
||||||
|
key format test 31f = Multiple tabs in key name
|
||||||
|
key format test 31g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[single tab before and random mixture blanks after key name]
|
||||||
|
keyformattest32a = No blanks in key name
|
||||||
|
key formattest32b = Single space in key name
|
||||||
|
key format test 32c = Multiple spaces in key name
|
||||||
|
key format test 32d = Multiple consecutive spaces in key name
|
||||||
|
key formattest32e = Single tab in key name
|
||||||
|
key format test 32f = Multiple tabs in key name
|
||||||
|
key format test 32g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[multiple tabs before and random mixture blanks after key name]
|
||||||
|
keyformattest33a = No blanks in key name
|
||||||
|
key formattest33b = Single space in key name
|
||||||
|
key format test 33c = Multiple spaces in key name
|
||||||
|
key format test 33d = Multiple consecutive spaces in key name
|
||||||
|
key formattest33e = Single tab in key name
|
||||||
|
key format test 33f = Multiple tabs in key name
|
||||||
|
key format test 33g = Multiple consecutive tabs in key name
|
||||||
|
|
||||||
|
[random mixture blanks before and after key name]
|
||||||
|
keyformattest34a = No blanks in key name
|
||||||
|
key formattest34b = Single space in key name
|
||||||
|
key format test 34c = Multiple spaces in key name
|
||||||
|
key format test 34d = Multiple consecutive spaces in key name
|
||||||
|
key formattest34e = Single tab in key name
|
||||||
|
key format test 34f = Multiple tabs in key name
|
||||||
|
key format test 34g = Multiple consecutive tabs in key name
|
||||||
234
bits/other-peoples/inifile.bash
Normal file
234
bits/other-peoples/inifile.bash
Normal file
|
|
@ -0,0 +1,234 @@
|
||||||
|
#!@BASH_PATH@
|
||||||
|
# Author: Jack L. Frost <fbt@fleshless.org>
|
||||||
|
# Licensed under the Internet Software Consortium (ISC) license.
|
||||||
|
# See LICENSE for its text.
|
||||||
|
|
||||||
|
_self="${0##*/}"
|
||||||
|
|
||||||
|
err() { printf '%s\n' "$*" >&2; }
|
||||||
|
|
||||||
|
debug() {
|
||||||
|
(( $flag_debug )) && { printf '%s\n' "DEBUG: $*"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
while read; do printf '%s\n' "$REPLY"; done <<- EOF
|
||||||
|
Usage: $_self [flags]
|
||||||
|
Flags:
|
||||||
|
-h|--help Show this message.
|
||||||
|
-c|--config <file> Use a config specified by <file>.
|
||||||
|
-d|--debug Enable debug messages.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_load() {
|
||||||
|
declare section line key value
|
||||||
|
declare -g -A cfg
|
||||||
|
|
||||||
|
mapfile -t config < "$1"
|
||||||
|
|
||||||
|
for line in "${config[@]}"; do
|
||||||
|
if [[ "$line" =~ ^\[.+\] ]]; then
|
||||||
|
section="${line//[\[\]]/}"
|
||||||
|
|
||||||
|
case "$section" in
|
||||||
|
main) :;;
|
||||||
|
*) ifaces+=( "${line//[\[\]]/}" );;
|
||||||
|
esac
|
||||||
|
elif [[ "$line" =~ ^('#'|\s+?$) ]]; then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
IFS='=' read -r key value <<< "$line"
|
||||||
|
|
||||||
|
if ! [[ "$section" ]]; then
|
||||||
|
err "Key $key does not belong to a section!"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$key" ]]; then
|
||||||
|
if ! [[ "$value" ]]; then
|
||||||
|
value=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${cfg[${section}_$key]} ]]; then
|
||||||
|
declare -g cfg["${section}_$key"]="${cfg[${section}_$key]}#${value}"
|
||||||
|
else
|
||||||
|
declare -g cfg["${section}_$key"]="$value"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
net_up() {
|
||||||
|
for iface in "${ifaces[@]}"; do
|
||||||
|
# Prepare the interface
|
||||||
|
if [[ "${cfg[${iface}_preup]}" ]]; then
|
||||||
|
${cfg[${iface}_preup]}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Bring the interface up
|
||||||
|
if [[ "${cfg[${iface}_up]}" ]]; then
|
||||||
|
${cfg[${iface}_up]}
|
||||||
|
else
|
||||||
|
if [[ "${cfg[${iface}_vlan_dev]}" ]]; then
|
||||||
|
ip link add link "${cfg[${iface}_vlan_dev]}" name "$iface" type vlan id "${cfg[${iface}_vlan_id]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ip link set "$iface" up
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add IPs
|
||||||
|
if [[ "${cfg[${iface}_ip]}" ]]; then
|
||||||
|
IFS='#' read -r -a ips <<< "${cfg[${iface}_ip]}"
|
||||||
|
|
||||||
|
for a in "${ips[@]}"; do
|
||||||
|
ip addr add "$a" dev "$iface"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Configure the interface with dhcp if needed
|
||||||
|
if [[ "${cfg[${iface}_dhcp]}" ]]; then
|
||||||
|
${cfg[main_dhcp_up]} "$iface"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add routes
|
||||||
|
if [[ "${cfg[${iface}_route]}" ]]; then
|
||||||
|
IFS='#' read -r -a routes <<< "${cfg[${iface}_route]}"
|
||||||
|
|
||||||
|
for r in "${routes[@]}"; do
|
||||||
|
read -r net gw <<< "$r"
|
||||||
|
|
||||||
|
ip route add "$net" via "$gw"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${cfg[${iface}_postup]}" ]]; then
|
||||||
|
${cfg[${iface}_up]}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
net_down() {
|
||||||
|
for iface in "${ifaces[@]}"; do
|
||||||
|
# Prepare the interface
|
||||||
|
if [[ "${cfg[${iface}_predown]}" ]]; then
|
||||||
|
${cfg[${iface}_predown]}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove routes
|
||||||
|
if [[ "${cfg[${iface}_route]}" ]]; then
|
||||||
|
IFS='#' read -r -a routes <<< "${cfg[${iface}_route]}"
|
||||||
|
|
||||||
|
for r in "${routes[@]}"; do
|
||||||
|
read -r net gw <<< "$r"
|
||||||
|
|
||||||
|
ip route del "$net" via "$gw"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stop dhcpcd
|
||||||
|
if [[ "${cfg[${iface}_dhcp]}" ]]; then
|
||||||
|
${cfg[main_dhcp_down]} "$iface"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove IPs
|
||||||
|
if [[ "${cfg[${iface}_ip]}" ]]; then
|
||||||
|
IFS='#' read -r -a ips <<< "${cfg[${iface}_ip]}"
|
||||||
|
|
||||||
|
for a in "${ips[@]}"; do
|
||||||
|
ip addr del "$a" dev "$iface"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Bring the interface down
|
||||||
|
if [[ "${cfg[${iface}_down]}" ]]; then
|
||||||
|
${cfg[${iface}_down]}
|
||||||
|
else
|
||||||
|
ip link set "$iface" down
|
||||||
|
|
||||||
|
if [[ "${cfg[${iface}_vlan_dev]}" ]]; then
|
||||||
|
ip link del "$iface"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${cfg[${iface}_postdown]}" ]]; then
|
||||||
|
${cfg[${iface}_postdown]}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
set_argv() {
|
||||||
|
declare arg opt c
|
||||||
|
declare -g argv
|
||||||
|
|
||||||
|
while (( $# )); do
|
||||||
|
unset -v arg opt c
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
(--) argv+=( "$1" ); break;;
|
||||||
|
|
||||||
|
(--*)
|
||||||
|
IFS='=' read arg opt <<< "$1"
|
||||||
|
argv+=( "$arg" )
|
||||||
|
|
||||||
|
[[ "$opt" ]] && {
|
||||||
|
argv+=( "$opt" )
|
||||||
|
}
|
||||||
|
;;
|
||||||
|
|
||||||
|
(-*)
|
||||||
|
while read -n1 c
|
||||||
|
do
|
||||||
|
case "$c" in
|
||||||
|
-|'') :;;
|
||||||
|
*) argv+=( "-$c" );;
|
||||||
|
esac
|
||||||
|
done <<< "$1"
|
||||||
|
;;
|
||||||
|
|
||||||
|
(*) argv+=( "$1" );;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
while (( $# )); do
|
||||||
|
case "$1" in
|
||||||
|
-h|--help) usage; return 0;;
|
||||||
|
-d|--debug)
|
||||||
|
flag_debug=1
|
||||||
|
debug "Debug flag set."
|
||||||
|
;;
|
||||||
|
-c|--config) cfg_file="$2"; shift;;
|
||||||
|
|
||||||
|
--) shift; break;;
|
||||||
|
-*)
|
||||||
|
err "Unknown key: $1"
|
||||||
|
usage
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
*) break;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! [[ "$cfg_file" ]]; then
|
||||||
|
cfg_file='@CONFDIR@/networking'
|
||||||
|
fi
|
||||||
|
|
||||||
|
cfg_load "$cfg_file" || {
|
||||||
|
return "$?"
|
||||||
|
}
|
||||||
|
|
||||||
|
action=${1:-"up"}
|
||||||
|
|
||||||
|
case "$action" in
|
||||||
|
up) net_up;;
|
||||||
|
down) net_down;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
set_argv "$@"
|
||||||
|
main "${argv[@]}"
|
||||||
3
bits/other-peoples/sites
Normal file
3
bits/other-peoples/sites
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
https://ajdiaz.wordpress.com/2008/02/09/bash-ini-parser/
|
||||||
|
https://github.com/rudimeier/bash_ini_parser
|
||||||
|
|
||||||
118
bits/other-peoples/someone_elses_bash_ini_parser/README
Normal file
118
bits/other-peoples/someone_elses_bash_ini_parser/README
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
|
||||||
|
bash_ini_parser -- Simple INI file parser
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
This is a comfortable and simple INI file parser to be used in
|
||||||
|
bash scripts.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
COPYRIGHT
|
||||||
|
---------
|
||||||
|
|
||||||
|
Copyright (c) 2009 Kevin Porter / Advanced Web Construction Ltd
|
||||||
|
(http://coding.tinternet.info / http://webutils.co.uk)
|
||||||
|
Copyright (c) 2010, 2011 Ruediger Meier <sweet_f_a@gmx.de>
|
||||||
|
(https://github.com/rudimeier/)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
USAGE
|
||||||
|
-----
|
||||||
|
|
||||||
|
You must source the bash file into your script:
|
||||||
|
|
||||||
|
> . read_ini.sh
|
||||||
|
|
||||||
|
and then use the read_ini function, defined as:
|
||||||
|
|
||||||
|
> read_ini INI_FILE [SECTION] [[--prefix|-p] PREFIX] [[--booleans|b] [0|1]]
|
||||||
|
|
||||||
|
If SECTION is supplied, then only the specified section of the file will
|
||||||
|
be processed.
|
||||||
|
|
||||||
|
After running the read_ini function, variables corresponding to the ini
|
||||||
|
file entries will be available to you. Naming convention for variable
|
||||||
|
names is:
|
||||||
|
|
||||||
|
PREFIX__SECTION__VARNAME
|
||||||
|
|
||||||
|
PREFIX is 'INI' by default (but can be changed with the --prefix option),
|
||||||
|
SECTION and VARNAME are the section name and variable name respectively.
|
||||||
|
For example, to read and output the variables of this ini file:
|
||||||
|
|
||||||
|
-- START test1.ini file
|
||||||
|
|
||||||
|
var1="VAR 1"
|
||||||
|
var2 = VAR 2
|
||||||
|
|
||||||
|
[section1]
|
||||||
|
var1="section1 VAR 1"
|
||||||
|
var2= section1 VAR 2
|
||||||
|
|
||||||
|
|
||||||
|
-- END test1.ini file
|
||||||
|
|
||||||
|
you could do this:
|
||||||
|
|
||||||
|
-- START bash script
|
||||||
|
|
||||||
|
. read_ini.sh
|
||||||
|
|
||||||
|
read_ini test1.ini
|
||||||
|
|
||||||
|
echo "var1 = ${INI__var1}"
|
||||||
|
echo "var2 = ${INI__var2}"
|
||||||
|
echo "section1 var1 = ${INI__section1__var1}"
|
||||||
|
echo "section1 var2 = ${INI__section1__var2}"
|
||||||
|
|
||||||
|
-- END bash script
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
-------
|
||||||
|
|
||||||
|
[--prefix | -p] PREFIX
|
||||||
|
String to prepend to generated variable names (automatically followed by '__').
|
||||||
|
Default: INI
|
||||||
|
|
||||||
|
[--booleans | -b] [0|1]
|
||||||
|
Whether to interpret special unquoted string values 'yes', 'no', 'true',
|
||||||
|
'false', 'on', 'off' as booleans.
|
||||||
|
Default: 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
INI FILE FORMAT
|
||||||
|
---------------
|
||||||
|
|
||||||
|
- Variables are stored as name/value pairs, eg:
|
||||||
|
var=value
|
||||||
|
|
||||||
|
- Leading and trailing whitespace of the name and the value is discarded.
|
||||||
|
|
||||||
|
- Use double or single quotes to get whitespace in the values
|
||||||
|
|
||||||
|
- Section names in square brackets, eg:
|
||||||
|
[section1]
|
||||||
|
var1 = value
|
||||||
|
|
||||||
|
- Variable names can be re-used between sections (or out of section), eg:
|
||||||
|
var1=value
|
||||||
|
[section1]
|
||||||
|
var1=value
|
||||||
|
[section3]
|
||||||
|
var1=value
|
||||||
|
|
||||||
|
- Dots are converted to underscores in all variable names.
|
||||||
|
|
||||||
|
- Special boolean values: unquoted strings 'yes', 'true' and 'on' are interpreted
|
||||||
|
as 1; 'no', 'false' and 'off' are interpreted as 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
7
bits/other-peoples/someone_elses_bash_ini_parser/TODO
Normal file
7
bits/other-peoples/someone_elses_bash_ini_parser/TODO
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
- Tabs/newlines to be preserved
|
||||||
|
|
||||||
|
- [] notation for arrays (like PHP's parse_ini_file())
|
||||||
|
|
||||||
|
|
||||||
272
bits/other-peoples/someone_elses_bash_ini_parser/read_ini.sh
Executable file
272
bits/other-peoples/someone_elses_bash_ini_parser/read_ini.sh
Executable file
|
|
@ -0,0 +1,272 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2009 Kevin Porter / Advanced Web Construction Ltd
|
||||||
|
# (http://coding.tinternet.info, http://webutils.co.uk)
|
||||||
|
# Copyright (c) 2010, 2011 Ruediger Meier <sweet_f_a@gmx.de>
|
||||||
|
# (https://github.com/rudimeier/)
|
||||||
|
#
|
||||||
|
# Simple INI file parser.
|
||||||
|
#
|
||||||
|
# See README for usage.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function read_ini()
|
||||||
|
{
|
||||||
|
# Be strict with the prefix, since it's going to be run through eval
|
||||||
|
function check_prefix()
|
||||||
|
{
|
||||||
|
if ! [[ "${VARNAME_PREFIX}" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]] ;then
|
||||||
|
echo "read_ini: invalid prefix '${VARNAME_PREFIX}'" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_ini_file()
|
||||||
|
{
|
||||||
|
if [ ! -r "$INI_FILE" ] ;then
|
||||||
|
echo "read_ini: '${INI_FILE}' doesn't exist or not" \
|
||||||
|
"readable" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# enable some optional shell behavior (shopt)
|
||||||
|
function pollute_bash()
|
||||||
|
{
|
||||||
|
if ! shopt -q extglob ;then
|
||||||
|
SWITCH_SHOPT="${SWITCH_SHOPT} extglob"
|
||||||
|
fi
|
||||||
|
if ! shopt -q nocasematch ;then
|
||||||
|
SWITCH_SHOPT="${SWITCH_SHOPT} nocasematch"
|
||||||
|
fi
|
||||||
|
shopt -q -s ${SWITCH_SHOPT}
|
||||||
|
}
|
||||||
|
|
||||||
|
# unset all local functions and restore shopt settings before returning
|
||||||
|
# from read_ini()
|
||||||
|
function cleanup_bash()
|
||||||
|
{
|
||||||
|
shopt -q -u ${SWITCH_SHOPT}
|
||||||
|
unset -f check_prefix check_ini_file pollute_bash cleanup_bash
|
||||||
|
}
|
||||||
|
|
||||||
|
local INI_FILE=""
|
||||||
|
local INI_SECTION=""
|
||||||
|
|
||||||
|
# {{{ START Deal with command line args
|
||||||
|
|
||||||
|
# Set defaults
|
||||||
|
local BOOLEANS=1
|
||||||
|
local VARNAME_PREFIX=INI
|
||||||
|
local CLEAN_ENV=0
|
||||||
|
|
||||||
|
# {{{ START Options
|
||||||
|
|
||||||
|
# Available options:
|
||||||
|
# --boolean Whether to recognise special boolean values: ie for 'yes', 'true'
|
||||||
|
# and 'on' return 1; for 'no', 'false' and 'off' return 0. Quoted
|
||||||
|
# values will be left as strings
|
||||||
|
# Default: on
|
||||||
|
#
|
||||||
|
# --prefix=STRING String to begin all returned variables with (followed by '__').
|
||||||
|
# Default: INI
|
||||||
|
#
|
||||||
|
# First non-option arg is filename, second is section name
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]
|
||||||
|
do
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
|
||||||
|
--clean | -c )
|
||||||
|
CLEAN_ENV=1
|
||||||
|
;;
|
||||||
|
|
||||||
|
--booleans | -b )
|
||||||
|
shift
|
||||||
|
BOOLEANS=$1
|
||||||
|
;;
|
||||||
|
|
||||||
|
--prefix | -p )
|
||||||
|
shift
|
||||||
|
VARNAME_PREFIX=$1
|
||||||
|
;;
|
||||||
|
|
||||||
|
* )
|
||||||
|
if [ -z "$INI_FILE" ]
|
||||||
|
then
|
||||||
|
INI_FILE=$1
|
||||||
|
else
|
||||||
|
if [ -z "$INI_SECTION" ]
|
||||||
|
then
|
||||||
|
INI_SECTION=$1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$INI_FILE" ] && [ "${CLEAN_ENV}" = 0 ] ;then
|
||||||
|
echo -e "Usage: read_ini [-c] [-b 0| -b 1]] [-p PREFIX] FILE"\
|
||||||
|
"[SECTION]\n or read_ini -c [-p PREFIX]" >&2
|
||||||
|
cleanup_bash
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! check_prefix ;then
|
||||||
|
cleanup_bash
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local INI_ALL_VARNAME="${VARNAME_PREFIX}__ALL_VARS"
|
||||||
|
if [ "${CLEAN_ENV}" = 1 ] ;then
|
||||||
|
eval unset "\$${INI_ALL_VARNAME}"
|
||||||
|
fi
|
||||||
|
unset ${INI_ALL_VARNAME}
|
||||||
|
|
||||||
|
if [ -z "$INI_FILE" ] ;then
|
||||||
|
cleanup_bash
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! check_ini_file ;then
|
||||||
|
cleanup_bash
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Sanitise BOOLEANS - interpret "0" as 0, anything else as 1
|
||||||
|
if [ "$BOOLEANS" != "0" ]
|
||||||
|
then
|
||||||
|
BOOLEANS=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# }}} END Options
|
||||||
|
|
||||||
|
# }}} END Deal with command line args
|
||||||
|
|
||||||
|
local LINE_NUM=0
|
||||||
|
local SECTION=""
|
||||||
|
|
||||||
|
# IFS is used in "read" and we want to switch it within the loop
|
||||||
|
local IFS=$' \t\n'
|
||||||
|
local IFS_OLD="${IFS}"
|
||||||
|
|
||||||
|
# we need some optional shell behavior (shopt) but want to restore
|
||||||
|
# current settings before returning
|
||||||
|
local SWITCH_SHOPT=""
|
||||||
|
pollute_bash
|
||||||
|
|
||||||
|
while read -r line
|
||||||
|
do
|
||||||
|
#echo line = "$line"
|
||||||
|
|
||||||
|
((LINE_NUM++))
|
||||||
|
|
||||||
|
# Skip blank lines and comments
|
||||||
|
if [ -z "$line" -o "${line:0:1}" = ";" -o "${line:0:1}" = "#" ]
|
||||||
|
then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Section marker?
|
||||||
|
if [[ "${line}" =~ ^\[[a-zA-Z0-9_]{1,}\]$ ]]
|
||||||
|
then
|
||||||
|
|
||||||
|
# Set SECTION var to name of section (strip [ and ] from section marker)
|
||||||
|
SECTION="${line#[}"
|
||||||
|
SECTION="${SECTION%]}"
|
||||||
|
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Are we getting only a specific section? And are we currently in it?
|
||||||
|
if [ ! -z "$INI_SECTION" ]
|
||||||
|
then
|
||||||
|
if [ "$SECTION" != "$INI_SECTION" ]
|
||||||
|
then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Valid var/value line? (check for variable name and then '=')
|
||||||
|
if ! [[ "${line}" =~ ^[a-zA-Z0-9._]{1,}[[:space:]]*= ]]
|
||||||
|
then
|
||||||
|
echo "Error: Invalid line:" >&2
|
||||||
|
echo " ${LINE_NUM}: $line" >&2
|
||||||
|
cleanup_bash
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# split line at "=" sign
|
||||||
|
IFS="="
|
||||||
|
read -r VAR VAL <<< "${line}"
|
||||||
|
IFS="${IFS_OLD}"
|
||||||
|
|
||||||
|
# delete spaces around the equal sign (using extglob)
|
||||||
|
VAR="${VAR%%+([[:space:]])}"
|
||||||
|
VAL="${VAL##+([[:space:]])}"
|
||||||
|
VAR=$(echo $VAR)
|
||||||
|
|
||||||
|
|
||||||
|
# Construct variable name:
|
||||||
|
# ${VARNAME_PREFIX}__$SECTION__$VAR
|
||||||
|
# Or if not in a section:
|
||||||
|
# ${VARNAME_PREFIX}__$VAR
|
||||||
|
# In both cases, full stops ('.') are replaced with underscores ('_')
|
||||||
|
if [ -z "$SECTION" ]
|
||||||
|
then
|
||||||
|
VARNAME=${VARNAME_PREFIX}__${VAR//./_}
|
||||||
|
else
|
||||||
|
VARNAME=${VARNAME_PREFIX}__${SECTION}__${VAR//./_}
|
||||||
|
fi
|
||||||
|
eval "${INI_ALL_VARNAME}=\"\$${INI_ALL_VARNAME} ${VARNAME}\""
|
||||||
|
|
||||||
|
if [[ "${VAL}" =~ ^\".*\"$ ]]
|
||||||
|
then
|
||||||
|
# remove existing double quotes
|
||||||
|
VAL="${VAL##\"}"
|
||||||
|
VAL="${VAL%%\"}"
|
||||||
|
elif [[ "${VAL}" =~ ^\'.*\'$ ]]
|
||||||
|
then
|
||||||
|
# remove existing single quotes
|
||||||
|
VAL="${VAL##\'}"
|
||||||
|
VAL="${VAL%%\'}"
|
||||||
|
elif [ "$BOOLEANS" = 1 ]
|
||||||
|
then
|
||||||
|
# Value is not enclosed in quotes
|
||||||
|
# Booleans processing is switched on, check for special boolean
|
||||||
|
# values and convert
|
||||||
|
|
||||||
|
# here we compare case insensitive because
|
||||||
|
# "shopt nocasematch"
|
||||||
|
case "$VAL" in
|
||||||
|
yes | true | on )
|
||||||
|
VAL=1
|
||||||
|
;;
|
||||||
|
no | false | off )
|
||||||
|
VAL=0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# enclose the value in single quotes and escape any
|
||||||
|
# single quotes and backslashes that may be in the value
|
||||||
|
VAL="${VAL//\\/\\\\}"
|
||||||
|
VAL="\$'${VAL//\'/\'}'"
|
||||||
|
|
||||||
|
eval "$VARNAME=$VAL"
|
||||||
|
done <"${INI_FILE}"
|
||||||
|
|
||||||
|
cleanup_bash
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
28
bits/other-peoples/someone_elses_bash_ini_parser/test/test.sh
Executable file
28
bits/other-peoples/someone_elses_bash_ini_parser/test/test.sh
Executable file
|
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
DIR=$(dirname $0)
|
||||||
|
cd $DIR
|
||||||
|
|
||||||
|
TESTS=$(ls test*.sh | grep -v test.sh | sed 's/\.sh$//')
|
||||||
|
|
||||||
|
for test in $TESTS
|
||||||
|
do
|
||||||
|
|
||||||
|
bash $test.sh &> $test.out
|
||||||
|
# bash $test.sh >$test.out 2>$test.err
|
||||||
|
|
||||||
|
# Fail and bail out if test didn't pass
|
||||||
|
PASSED=$(diff $test.out $test.out.correct 2>&1)
|
||||||
|
if [ ! -z "$PASSED" ]
|
||||||
|
then
|
||||||
|
echo "Test $test failed. Output is in $DIR/$test.out"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
rm -rf $test.out
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
echo "All tests passed"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
|
||||||
|
; Comment beginning with ';'
|
||||||
|
# Comment beginning with '#'
|
||||||
|
|
||||||
|
; var1 - simple var
|
||||||
|
var1=VAR 1
|
||||||
|
|
||||||
|
; var2 - space before '='; leading space that should be stripped
|
||||||
|
var2 = VAR 2
|
||||||
|
|
||||||
|
; var3 - with leading and trailing space that should be stripped
|
||||||
|
var3 = VAR 3
|
||||||
|
|
||||||
|
; var4 - value in double quotes
|
||||||
|
var4="VAR 4"
|
||||||
|
|
||||||
|
; var5 - value in double quotes; value's leading and trailing whitespace should
|
||||||
|
; be preserved; leading and trailing whitespace before/after double quotes should
|
||||||
|
; not become part of the value
|
||||||
|
var5 = " VAR 5 "
|
||||||
|
|
||||||
|
; var6 - value in double quotes; value's leading and trailing whitespace should
|
||||||
|
; be preserved; leading and trailing whitespace before/after double quotes should
|
||||||
|
; not become part of the value
|
||||||
|
var6 = ' VAR 6 '
|
||||||
|
|
||||||
|
; var7 - value contains a single double quote
|
||||||
|
var7 = VAR " 7
|
||||||
|
|
||||||
|
; var8 - value contains a single single quote
|
||||||
|
var8 = VAR ' 8
|
||||||
|
|
||||||
|
; var9 - leading whitespace before variable name
|
||||||
|
var9=VAR 9
|
||||||
|
|
||||||
|
; var10 - leading whitespace before variable name
|
||||||
|
var10 = VAR 10
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
var1:VAR 1
|
||||||
|
var2:VAR 2
|
||||||
|
var3:VAR 3
|
||||||
|
var4:VAR 4
|
||||||
|
var5: VAR 5
|
||||||
|
var6: VAR 6
|
||||||
|
var7:VAR " 7
|
||||||
|
var8:VAR ' 8
|
||||||
|
var9:VAR 9
|
||||||
|
var10:VAR 10
|
||||||
21
bits/other-peoples/someone_elses_bash_ini_parser/test/test1.sh
Executable file
21
bits/other-peoples/someone_elses_bash_ini_parser/test/test1.sh
Executable file
|
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
|
||||||
|
# Test 1
|
||||||
|
#
|
||||||
|
# Basic variable values; leading/trailing whitespace; comments
|
||||||
|
|
||||||
|
. ../read_ini.sh
|
||||||
|
read_ini test1.ini
|
||||||
|
|
||||||
|
#echo "a:LOCALVAR=$LOCALVAR"
|
||||||
|
echo "var1:$INI__var1"
|
||||||
|
echo "var2:$INI__var2"
|
||||||
|
echo "var3:$INI__var3"
|
||||||
|
echo "var4:$INI__var4"
|
||||||
|
echo "var5:$INI__var5"
|
||||||
|
echo "var6:$INI__var6"
|
||||||
|
echo "var7:$INI__var7"
|
||||||
|
echo "var8:$INI__var8"
|
||||||
|
echo "var9:$INI__var9"
|
||||||
|
echo "var10:$INI__var10"
|
||||||
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
|
||||||
|
var1=VAR1
|
||||||
|
|
||||||
|
; Invalid line - should throw an error and stop processing
|
||||||
|
INVALID LINE
|
||||||
|
var2=VAR2
|
||||||
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
Error: Invalid line:
|
||||||
|
6: INVALID LINE
|
||||||
8
bits/other-peoples/someone_elses_bash_ini_parser/test/test2.sh
Executable file
8
bits/other-peoples/someone_elses_bash_ini_parser/test/test2.sh
Executable file
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
# Test 2
|
||||||
|
#
|
||||||
|
# Invalid line
|
||||||
|
|
||||||
|
. ../read_ini.sh
|
||||||
|
read_ini test2.ini
|
||||||
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
; Testing sections
|
||||||
|
|
||||||
|
var1=VAR 1
|
||||||
|
var2= "VAR 2 "
|
||||||
|
|
||||||
|
[section1]
|
||||||
|
var1="section 1 VAR 1"
|
||||||
|
var2= "section 1 VAR 2"
|
||||||
|
var3 = "section 1 VAR 3 "
|
||||||
|
|
||||||
|
[section2]
|
||||||
|
var1 = section 2 VAR 1
|
||||||
|
var2=" section 2 VAR 2"
|
||||||
|
var3=section 2 VAR 3
|
||||||
|
var4=section 2 VAR 4
|
||||||
|
var5=section 2 VAR 5
|
||||||
|
|
||||||
|
[section3]
|
||||||
|
var1="section 3 VAR 1"
|
||||||
|
var2= "section 3 VAR 2"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
var1:VAR 1
|
||||||
|
var2:VAR 2
|
||||||
|
setion1_var1:section 1 VAR 1
|
||||||
|
setion1_var2:section 1 VAR 2
|
||||||
|
setion1_var3:section 1 VAR 3
|
||||||
|
setion2_var1:section 2 VAR 1
|
||||||
|
setion2_var2: section 2 VAR 2
|
||||||
|
setion2_var3:section 2 VAR 3
|
||||||
|
setion2_var4:section 2 VAR 4
|
||||||
|
setion2_var5:section 2 VAR 5
|
||||||
|
setion3_var1:section 3 VAR 1
|
||||||
|
setion3_var2:section 3 VAR 2
|
||||||
25
bits/other-peoples/someone_elses_bash_ini_parser/test/test3.sh
Executable file
25
bits/other-peoples/someone_elses_bash_ini_parser/test/test3.sh
Executable file
|
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
# Test 3
|
||||||
|
#
|
||||||
|
# Sections
|
||||||
|
|
||||||
|
. ../read_ini.sh
|
||||||
|
read_ini test3.ini
|
||||||
|
|
||||||
|
echo "var1:$INI__var1"
|
||||||
|
echo "var2:$INI__var2"
|
||||||
|
|
||||||
|
echo "setion1_var1:$INI__section1__var1"
|
||||||
|
echo "setion1_var2:$INI__section1__var2"
|
||||||
|
echo "setion1_var3:$INI__section1__var3"
|
||||||
|
|
||||||
|
echo "setion2_var1:$INI__section2__var1"
|
||||||
|
echo "setion2_var2:$INI__section2__var2"
|
||||||
|
echo "setion2_var3:$INI__section2__var3"
|
||||||
|
echo "setion2_var4:$INI__section2__var4"
|
||||||
|
echo "setion2_var5:$INI__section2__var5"
|
||||||
|
|
||||||
|
echo "setion3_var1:$INI__section3__var1"
|
||||||
|
echo "setion3_var2:$INI__section3__var2"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
; Testing dots in variable names (these get converted to underscores in
|
||||||
|
; output variable names)
|
||||||
|
|
||||||
|
var.1 = "VAR 1"
|
||||||
|
var.two="VAR 2"
|
||||||
|
var.3.two_dots="VAR 3"
|
||||||
|
|
||||||
|
|
||||||
|
[section1]
|
||||||
|
var.1="section 1 VAR 1"
|
||||||
|
var.two="section 1 VAR 2"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
var_1:VAR 1
|
||||||
|
var_two:VAR 2
|
||||||
|
var_3_two_dots:VAR 3
|
||||||
|
section 1 var_1:section 1 VAR 1
|
||||||
|
section 1 var_two:section 1 VAR 2
|
||||||
15
bits/other-peoples/someone_elses_bash_ini_parser/test/test4.sh
Executable file
15
bits/other-peoples/someone_elses_bash_ini_parser/test/test4.sh
Executable file
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
# Test 4
|
||||||
|
#
|
||||||
|
# Dots in variable names (converted to underscores in output var names)
|
||||||
|
|
||||||
|
. ../read_ini.sh
|
||||||
|
read_ini test4.ini
|
||||||
|
|
||||||
|
echo "var_1:$INI__var_1"
|
||||||
|
echo "var_two:$INI__var_two"
|
||||||
|
echo "var_3_two_dots:$INI__var_3_two_dots"
|
||||||
|
|
||||||
|
echo "section 1 var_1:$INI__section1__var_1"
|
||||||
|
echo "section 1 var_two:$INI__section1__var_two"
|
||||||
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
; Testing prevention of in-value code execution via eval
|
||||||
|
var1 = blah blah `ls` blah
|
||||||
|
var2 = blah blah $(ls) blah
|
||||||
|
|
||||||
|
; these code injections worked on 0.3
|
||||||
|
var3 = blah blah \\`ls\\` blah
|
||||||
|
var4 = blah blah \\$(ls) blah
|
||||||
|
|
||||||
|
; these code injections could work with read -r
|
||||||
|
var5 = blah blah \`ls\` blah
|
||||||
|
var6 = blah blah \$(ls) blah
|
||||||
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
var1:blah blah `ls` blah
|
||||||
|
var2:blah blah $(ls) blah
|
||||||
|
var3:blah blah \\`ls\\` blah
|
||||||
|
var4:blah blah \\$(ls) blah
|
||||||
|
var5:blah blah \`ls\` blah
|
||||||
|
var6:blah blah \$(ls) blah
|
||||||
16
bits/other-peoples/someone_elses_bash_ini_parser/test/test5.sh
Executable file
16
bits/other-peoples/someone_elses_bash_ini_parser/test/test5.sh
Executable file
|
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
|
||||||
|
# Test 5
|
||||||
|
#
|
||||||
|
# Prevention of in-value code execution via backticks or $() notation.
|
||||||
|
# This must be done because the value is run through an eval statement.
|
||||||
|
|
||||||
|
. ../read_ini.sh
|
||||||
|
read_ini test5.ini
|
||||||
|
|
||||||
|
echo "var1:$INI__var1"
|
||||||
|
echo "var2:$INI__var2"
|
||||||
|
echo "var3:$INI__var3"
|
||||||
|
echo "var4:$INI__var4"
|
||||||
|
echo "var5:$INI__var5"
|
||||||
|
echo "var6:$INI__var6"
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
|
||||||
|
|
||||||
|
; Testing processing of special boolean constants: unquoted
|
||||||
|
; strings 'yes', 'true' and 'on' are interpreted as 1;
|
||||||
|
; unquoted strings 'no', 'false' and 'off' as 0.
|
||||||
|
|
||||||
|
yes1 = yes
|
||||||
|
yes2 = "yes"
|
||||||
|
yes3 = Yes
|
||||||
|
true1=true
|
||||||
|
true2= true
|
||||||
|
true3 = "tRuE"
|
||||||
|
on1 = on
|
||||||
|
on2 = oN
|
||||||
|
on3 = "ON"
|
||||||
|
|
||||||
|
no1 = no
|
||||||
|
no2 = "no"
|
||||||
|
no3=No
|
||||||
|
false1 = false
|
||||||
|
false2 = faLSe
|
||||||
|
false3 = "FALSE"
|
||||||
|
off1 = off
|
||||||
|
off2 = Off
|
||||||
|
off3 = "off"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
yes1:1
|
||||||
|
yes2:yes
|
||||||
|
yes3:1
|
||||||
|
true1:1
|
||||||
|
true2:1
|
||||||
|
true3:tRuE
|
||||||
|
on1:1
|
||||||
|
on2:1
|
||||||
|
on3:ON
|
||||||
|
no1:0
|
||||||
|
no2:no
|
||||||
|
no3:0
|
||||||
|
false1:0
|
||||||
|
false2:0
|
||||||
|
false3:FALSE
|
||||||
|
off1:0
|
||||||
|
off2:0
|
||||||
|
off3:off
|
||||||
|
yes1:1
|
||||||
|
true2:1
|
||||||
|
on3:ON
|
||||||
|
no3:0
|
||||||
|
false2:0
|
||||||
|
off1:0
|
||||||
|
yes1:yes
|
||||||
|
true2:true
|
||||||
|
on3:ON
|
||||||
|
no3:No
|
||||||
|
false2:faLSe
|
||||||
|
off1:off
|
||||||
56
bits/other-peoples/someone_elses_bash_ini_parser/test/test6.sh
Executable file
56
bits/other-peoples/someone_elses_bash_ini_parser/test/test6.sh
Executable file
|
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
# Testing booleans processing
|
||||||
|
|
||||||
|
# First: with default booleans processing (on)
|
||||||
|
. ../read_ini.sh
|
||||||
|
read_ini test6.ini
|
||||||
|
|
||||||
|
echo "yes1:$INI__yes1"
|
||||||
|
echo "yes2:$INI__yes2"
|
||||||
|
echo "yes3:$INI__yes3"
|
||||||
|
echo "true1:$INI__true1"
|
||||||
|
echo "true2:$INI__true2"
|
||||||
|
echo "true3:$INI__true3"
|
||||||
|
echo "on1:$INI__on1"
|
||||||
|
echo "on2:$INI__on2"
|
||||||
|
echo "on3:$INI__on3"
|
||||||
|
|
||||||
|
echo "no1:$INI__no1"
|
||||||
|
echo "no2:$INI__no2"
|
||||||
|
echo "no3:$INI__no3"
|
||||||
|
echo "false1:$INI__false1"
|
||||||
|
echo "false2:$INI__false2"
|
||||||
|
echo "false3:$INI__false3"
|
||||||
|
echo "off1:$INI__off1"
|
||||||
|
echo "off2:$INI__off2"
|
||||||
|
echo "off3:$INI__off3"
|
||||||
|
|
||||||
|
|
||||||
|
# Second: with booleans processing explicitly turned on via "--booleans 1"
|
||||||
|
. ../read_ini.sh
|
||||||
|
read_ini --booleans 1 test6.ini
|
||||||
|
|
||||||
|
echo "yes1:$INI__yes1"
|
||||||
|
echo "true2:$INI__true2"
|
||||||
|
echo "on3:$INI__on3"
|
||||||
|
|
||||||
|
echo "no3:$INI__no3"
|
||||||
|
echo "false2:$INI__false2"
|
||||||
|
echo "off1:$INI__off1"
|
||||||
|
|
||||||
|
|
||||||
|
# Third: with booleans processing explicity switched off via "--booleans 0"
|
||||||
|
. ../read_ini.sh
|
||||||
|
read_ini test6.ini --booleans 0
|
||||||
|
|
||||||
|
echo "yes1:$INI__yes1"
|
||||||
|
echo "true2:$INI__true2"
|
||||||
|
echo "on3:$INI__on3"
|
||||||
|
|
||||||
|
echo "no3:$INI__no3"
|
||||||
|
echo "false2:$INI__false2"
|
||||||
|
echo "off1:$INI__off1"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
; Simple definitions for testing --prefix option
|
||||||
|
|
||||||
|
var1=VAR 1
|
||||||
|
|
||||||
|
[section1]
|
||||||
|
var1 = "section 1 VAR 1"
|
||||||
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
# 1
|
||||||
|
var1:VAR 1
|
||||||
|
section1 var1:section 1 VAR 1
|
||||||
|
# 2
|
||||||
|
read_ini: invalid prefix 'PR:EFIX,'
|
||||||
|
# 3
|
||||||
|
read_ini: invalid prefix '1PREFIX'
|
||||||
30
bits/other-peoples/someone_elses_bash_ini_parser/test/test7.sh
Executable file
30
bits/other-peoples/someone_elses_bash_ini_parser/test/test7.sh
Executable file
|
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
# Test 7
|
||||||
|
#
|
||||||
|
# Option: [--prefix | -p] PREFIX
|
||||||
|
|
||||||
|
# First: valid value for prefix
|
||||||
|
echo "# 1"
|
||||||
|
. ../read_ini.sh
|
||||||
|
read_ini test7.ini --prefix PREFIX1
|
||||||
|
|
||||||
|
echo "var1:$PREFIX1__var1"
|
||||||
|
echo "section1 var1:$PREFIX1__section1__var1"
|
||||||
|
|
||||||
|
# Second: invalid value for prefix (contains illegal chars)
|
||||||
|
echo "# 2"
|
||||||
|
. ../read_ini.sh
|
||||||
|
read_ini -p PR:EFIX, test7.ini &&
|
||||||
|
{
|
||||||
|
echo "var1:$PREFIX1__var1"
|
||||||
|
echo "section1 var1:$PREFIX1__section1__var1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Third: invalid value for prefix (begins with a number)
|
||||||
|
echo "# 3"
|
||||||
|
. ../read_ini.sh
|
||||||
|
read_ini --prefix 1PREFIX test7.ini &&
|
||||||
|
{
|
||||||
|
echo "var1:$PREFIX1__var1"
|
||||||
|
echo "section1 var1:$PREFIX1__section1__var1"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
; this code injection via section worked on 0.3
|
||||||
|
[x=blah; ls ;]
|
||||||
|
var1 = blah
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
Error: Invalid line:
|
||||||
|
3: [x=blah; ls ;]
|
||||||
9
bits/other-peoples/someone_elses_bash_ini_parser/test/test8.sh
Executable file
9
bits/other-peoples/someone_elses_bash_ini_parser/test/test8.sh
Executable file
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
|
||||||
|
# Test 8
|
||||||
|
#
|
||||||
|
# Prevention of in-value code execution via invalid section
|
||||||
|
|
||||||
|
. ../read_ini.sh
|
||||||
|
read_ini test8.ini
|
||||||
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
; Testing quoted quotes (didnt't worked in 0.3)
|
||||||
|
|
||||||
|
; code injection
|
||||||
|
var1="" ls "."
|
||||||
|
var2='' ls '.'
|
||||||
|
|
||||||
|
; or just an error: unexpected EOF while looking for matching `"'
|
||||||
|
var3="""
|
||||||
|
var4='''
|
||||||
|
var5="
|
||||||
|
var6='
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
var1:" ls ".
|
||||||
|
var2:' ls '.
|
||||||
|
var3:"
|
||||||
|
var4:'
|
||||||
|
var5:"
|
||||||
|
var6:'
|
||||||
16
bits/other-peoples/someone_elses_bash_ini_parser/test/test9.sh
Executable file
16
bits/other-peoples/someone_elses_bash_ini_parser/test/test9.sh
Executable file
|
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
# Test 9
|
||||||
|
#
|
||||||
|
# further stuff which didn't worked in 0.3
|
||||||
|
|
||||||
|
. ../read_ini.sh
|
||||||
|
if ! read_ini test9.ini ;then exit 1; fi
|
||||||
|
|
||||||
|
|
||||||
|
echo "var1:$INI__var1"
|
||||||
|
echo "var2:$INI__var2"
|
||||||
|
echo "var3:$INI__var3"
|
||||||
|
echo "var4:$INI__var4"
|
||||||
|
echo "var5:$INI__var5"
|
||||||
|
echo "var6:$INI__var6"
|
||||||
|
|
||||||
1
bits/other-peoples/someone_elses_bash_ini_parser/url
Normal file
1
bits/other-peoples/someone_elses_bash_ini_parser/url
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
https://github.com/rudimeier/bash_ini_parser
|
||||||
34
bits/quotes-sed.sh
Normal file
34
bits/quotes-sed.sh
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
{ echo "keyname1 = line without quotes"
|
||||||
|
echo "keyname2 = line with 1 \" double quote"
|
||||||
|
echo "keyname3 = line with \" 2 double \" quotes"
|
||||||
|
echo "keyname4 = line \\"
|
||||||
|
echo "with continuation \\"
|
||||||
|
echo "at end"
|
||||||
|
echo "keyname5 = \"double quoted text, single line\""
|
||||||
|
echo "keyname6 = 'single quoted text, single line'"
|
||||||
|
echo "keyname7 = \"double quoted text"
|
||||||
|
echo "over 1"
|
||||||
|
echo "2"
|
||||||
|
echo "3"
|
||||||
|
echo "4 \""; } |
|
||||||
|
sed -re "{
|
||||||
|
# Insert [ at beginning of key
|
||||||
|
s/^[[:blank:]]*/['/
|
||||||
|
# Insert ] at end of key
|
||||||
|
s/[[:blank:]]*=/']=/
|
||||||
|
# Branch if there's a =<quote> ...
|
||||||
|
/^.*[^\\]=[[:blank:]]*['\"]/ {
|
||||||
|
p
|
||||||
|
:x
|
||||||
|
# Branch if there is no <quote> at end of line ...
|
||||||
|
/.*['\"][[:blank:]]*\$/ ! {
|
||||||
|
# Read new line
|
||||||
|
N
|
||||||
|
# Insert a \n
|
||||||
|
s/\\\n//
|
||||||
|
# Continue loop if s/ above was successful
|
||||||
|
tx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s/(^|$)/#/g
|
||||||
|
}"
|
||||||
76
bits/readline/readline
Executable file
76
bits/readline/readline
Executable file
|
|
@ -0,0 +1,76 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
shopt -s extglob
|
||||||
|
|
||||||
|
exec {FD}<readline.ini
|
||||||
|
|
||||||
|
#key2value() {
|
||||||
|
# # SECTION=
|
||||||
|
# KEY="$1"
|
||||||
|
#
|
||||||
|
# if [[ "${VALUE:0:1}" =~ [\"\'] ]]; then
|
||||||
|
# printf "%s" "${VALUE:1:-1}"
|
||||||
|
# else
|
||||||
|
# printf "%s" "$VALUE"
|
||||||
|
# fi
|
||||||
|
#}
|
||||||
|
|
||||||
|
while :; do
|
||||||
|
LINE=""
|
||||||
|
while :; do
|
||||||
|
# The 'read' will remove leading whitespace from the line.
|
||||||
|
read -r -u $FD REPLY || break 2
|
||||||
|
|
||||||
|
# Handle line continuations.
|
||||||
|
if [[ "${REPLY: -1:1}" == "\\" ]]; then
|
||||||
|
LINE+="${REPLY:0:-1}"
|
||||||
|
continue
|
||||||
|
else
|
||||||
|
LINE+="$REPLY"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Ignore the line if it's a comment.
|
||||||
|
# FIXME: Make it so the comments can be # or ; or both.
|
||||||
|
[[ "$LINE" =~ ^[[:blank:]]*([#\;].*)*$ ]] && continue
|
||||||
|
|
||||||
|
# Remove trailing whitespace from key part.
|
||||||
|
LINE="${LINE/+([[:blank:]])=/=}"
|
||||||
|
|
||||||
|
# Remove leading whitespace from value part.
|
||||||
|
LINE="${LINE/=+([[:blank:]])/=}"
|
||||||
|
|
||||||
|
# Extract the key and the value
|
||||||
|
KEY="${LINE%%=*}"
|
||||||
|
VALUE="${LINE#*=}"
|
||||||
|
|
||||||
|
# If the value starts with a " or ' it must end with same.
|
||||||
|
if [[ "${VALUE:0:1}" =~ [\"\'] ]]; then
|
||||||
|
if [[ "${VALUE:0:1}" != "${VALUE: -1:1}" ]]; then
|
||||||
|
echo "Unmatched quotes - ignoring line."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
printf "<%s> = <%s>\n" "$KEY" "$VALUE"
|
||||||
|
|
||||||
|
unset FOO
|
||||||
|
declare -A FOO
|
||||||
|
FOO["$KEY"]=$VALUE
|
||||||
|
printf "%s\n" "$(key2value "$KEY")"
|
||||||
|
|
||||||
|
# printf "%q\n" "$VALUE"
|
||||||
|
# declare -p FOO
|
||||||
|
echo
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# FOO="test1 = test2 = test3"
|
||||||
|
# KEY="${FOO%%=*}"
|
||||||
|
# VALUE="${FOO#*=}"
|
||||||
18
bits/readline/readline.ini
Normal file
18
bits/readline/readline.ini
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# test
|
||||||
|
; test
|
||||||
|
# test
|
||||||
|
; test
|
||||||
|
foo = This is a line with \
|
||||||
|
a backslash \
|
||||||
|
# foo
|
||||||
|
\
|
||||||
|
|
||||||
|
#bar = This is a line without a backslash
|
||||||
|
|
||||||
|
#baz = " This is a = \
|
||||||
|
# line in \
|
||||||
|
#quotes "
|
||||||
|
|
||||||
|
foo = 'Test \' $BASH_SOURCE'
|
||||||
|
bar = "Test 2 ' \""
|
||||||
|
#foof = This is $BASH_SOURCE line without quotes
|
||||||
23
bits/sanatise_section/sanatise_section
Executable file
23
bits/sanatise_section/sanatise_section
Executable file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
INIFILE=sanatise_section.ini
|
||||||
|
|
||||||
|
|
||||||
|
if ! exec 10<"$INIFILE"; then
|
||||||
|
echo "${0##*/}: $INIFILE: failed to open"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
shopt -s extglob
|
||||||
|
|
||||||
|
# Parse the ini file
|
||||||
|
IFS=$'\n'
|
||||||
|
BUFFER=""
|
||||||
|
while :; do
|
||||||
|
# Read a line of input from the file descriptor
|
||||||
|
read -u 10 LINE || break
|
||||||
|
# printf -- "->%s<-\n" "$LINE"
|
||||||
|
LINE="${LINE/#*([[:blank:]])\[*([[:blank:]])/}"
|
||||||
|
LINE="${LINE/%*([[:blank:]])\]*([[:blank:]])/}"
|
||||||
|
printf -- "->%s<-\n" "$LINE"
|
||||||
|
done
|
||||||
8
bits/sanatise_section/sanatise_section.ini
Normal file
8
bits/sanatise_section/sanatise_section.ini
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
[test 1]
|
||||||
|
[ test 2]
|
||||||
|
[ test 3 ]
|
||||||
|
[ test 4 ]
|
||||||
|
[ test 5 ]
|
||||||
|
[ test 6 ]
|
||||||
|
[ test 7 ]
|
||||||
|
[test 8]
|
||||||
185
bits/sed-parser/sed-parser-simplified.sh
Normal file
185
bits/sed-parser/sed-parser-simplified.sh
Normal file
|
|
@ -0,0 +1,185 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Notes:
|
||||||
|
# Cannot use any of the deliminators in the key name
|
||||||
|
# Todo:
|
||||||
|
# Lines beginning with #; within " .. " blocks on new lines will be stripped.
|
||||||
|
# Allow merging of multiple sections with the same name
|
||||||
|
# Change case of variables: \L \U \E
|
||||||
|
# export SECLIST="SECTIONS"
|
||||||
|
# Allow delims to be specified in a var - don't assume =:
|
||||||
|
|
||||||
|
export VARPREFIX="INI_"
|
||||||
|
export SECPREFIX="SECTION_"
|
||||||
|
export SECCNAMEKEY="%cannonical name%"
|
||||||
|
export TOPSEC="global"
|
||||||
|
initest() {
|
||||||
|
echo "declare -A ${VARPREFIX}${SECPREFIX}${TOPSEC}=("
|
||||||
|
echo "[${SECCNAMEKEY}]=\"${TOPSEC}\""
|
||||||
|
cat $1 | sed -r "{
|
||||||
|
# Ignore blank lines and comments
|
||||||
|
/^[[:blank:]]*(#|;|$)/ d
|
||||||
|
# Handle [section] lines
|
||||||
|
/^[[:blank:]]*\[.*\][[:blank:]]*$/ {
|
||||||
|
i )
|
||||||
|
s/(^[[:blank:]]*\[[[:blank:]]*|[[:blank:]]*\][[:blank:]]*$)//g
|
||||||
|
h
|
||||||
|
s/([[:blank:]]+|[^[:alnum:]])/_/g
|
||||||
|
s/(.*)/declare -A ${VARPREFIX}${SECPREFIX}\1=(/p
|
||||||
|
g
|
||||||
|
s/(.*)/ \[${SECCNAMEKEY}\]=\"\1\"/
|
||||||
|
b
|
||||||
|
}
|
||||||
|
# FIXME: This needs to pick up escaped =:s
|
||||||
|
/^([[:blank:]]*[^[:blank:]]+[[:blank:]]*)+[=:].*$/ {
|
||||||
|
# Escape any ] characters within key name - bash <4.3 can't handle them
|
||||||
|
s/^(([^\]]*)\[+)*([=:].*)$/\2\\\\\]\3/
|
||||||
|
# Escape any ' characters within the key name
|
||||||
|
s/^[[:blank:]]*/ \[\'/
|
||||||
|
s/[[:blank:]]*[=:][[:blank:]]*(.*)$/\']=\1/
|
||||||
|
########s/([\"]+)/\\\\\1/g
|
||||||
|
#s/^(\[')([']+)('\].*)/\1X\3/g
|
||||||
|
# s/[[:blank:]]*[=:][[:blank:]]*[\"\'\`]?(.*)$/\]=\'\1/
|
||||||
|
# s/^[[:blank:]]*([[:print:]]+)[[:blank:]]*[=:][[:blank:]]*/\[\1\]=/
|
||||||
|
b
|
||||||
|
}
|
||||||
|
q
|
||||||
|
}"
|
||||||
|
echo ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
; initest
|
||||||
|
|
||||||
|
# Join lines ending in \ :
|
||||||
|
sed ':x; /\\$/ { N; s/\\\n//; tx }' textfile
|
||||||
|
|
||||||
|
echo 'ao ao ao | ao' | sed 'h; s/.*|/|/; x; s/|.*//; s/o/x/g; G; s/\n//'
|
||||||
|
|
||||||
|
|
||||||
|
# if a line ends with a backslash, append the next line to it
|
||||||
|
sed -e :a -e '/\\$/N; s/\\\n//; ta'
|
||||||
|
|
||||||
|
|
||||||
|
# 4.0 needs the backslash escaped AND the ] when referencing the element
|
||||||
|
06:09 <Tadgy> 40# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}"
|
||||||
|
06:09 <shbot> declare -A FOOF='([test\\\]test]="test" )'
|
||||||
|
06:09 <shbot> <>
|
||||||
|
06:11 <Tadgy> 40# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\\\]test']}"
|
||||||
|
06:11 <shbot> declare -A FOOF='([test\\\]test]="test" )'
|
||||||
|
06:11 <shbot> <test>
|
||||||
|
|
||||||
|
# 4.1, 4.2, 4.3 are consistent with this syntax
|
||||||
|
06:06 <Tadgy> 41# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}"
|
||||||
|
06:06 <shbot> declare -A FOOF='(["test\\]test"]="test" )'
|
||||||
|
06:06 <shbot> <test>
|
||||||
|
06:08 <Tadgy> 42# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}"
|
||||||
|
06:08 <shbot> declare -A FOOF='(["test\\]test"]="test" )'
|
||||||
|
06:08 <shbot> <test>
|
||||||
|
06:09 <Tadgy> 43# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}"
|
||||||
|
06:09 <shbot> declare -A FOOF='(["test\\]test"]="test" )'
|
||||||
|
06:09 <shbot> <test>
|
||||||
|
#Works without escapes in 4.3:
|
||||||
|
06:08 <Tadgy> 43# declare -A FOOF=( ['test]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test]test']}"
|
||||||
|
06:08 <shbot> declare -A FOOF='(["test]test"]="test" )'
|
||||||
|
06:08 <shbot> <test>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[ [ invalid-section###3 ] $$ ] $
|
||||||
|
[ invalid-section###3 ] $$X
|
||||||
|
# Squash multiple blanks and invalid chars to single _ -- s/[^[:alnum:]]+/_/g
|
||||||
|
_invalid_section_3_
|
||||||
|
# Blanks and invalid chars replaced with _ no sqash -- s/[^[:alnum:]]/_/g
|
||||||
|
_________invalid_section___3_______
|
||||||
|
# Squash multiple blanks to single _ and replace invalid chars with _ -- s/([[:blank:]]+|[^[:alnum:]])/_/g
|
||||||
|
__invalid_section___3_____
|
||||||
|
|
||||||
|
|
||||||
|
#s/[[:blank:]]*\][[:blank:]]*[^[:alnum:]]+/_/g
|
||||||
|
# s/^[[:blank:]]*\[[[:blank:]]*/declare -A ${VAR}_/
|
||||||
|
# s/[[:blank:]]*\][[:blank:]]*$/=(/
|
||||||
|
|
||||||
|
# s/(^[[:blank:]]*\[[[:blank:]]*)|([[:blank:]]*\][[:blank:]]*$)/X/g
|
||||||
|
# s/[[:blank:]]+/ /g
|
||||||
|
# s/^[[:blank:]]*\[[[:blank:]]*([[:graph:]]*)[[:blank:]]*\][[:blank:]]*$/[\1]/
|
||||||
|
l 120
|
||||||
|
# s/^[[:blank:]]*(\[|\]) [[:blank:]]*$/\1/g
|
||||||
|
# s/([^[:alnum:]]|_+)/_/g
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
|
||||||
|
s/[[:blank:]]*(\[|\])[[:blank:]]*/\1/g
|
||||||
|
s/([^[:alnum:]]|_+)/_/g
|
||||||
|
|
||||||
|
|
||||||
|
label regex jump back if s was done
|
||||||
|
|
||||||
|
|
||||||
|
# s/\[_*([^]]*)/declare -A ${VAR}_\1=(/
|
||||||
|
# s/\[_*(.*)_*\].*/declare -A ${VAR}_\1=(/
|
||||||
|
# s/[[:blank:]]*\[(.*)\].*/declare -A ${VAR}_\1=(/
|
||||||
|
}
|
||||||
|
# /^(\)|declare -A)/ ! {
|
||||||
|
# s/^[[:blank:]]*/\[/
|
||||||
|
# s/[[:blank:]]*=[[:blank:]]*/\]=\"/
|
||||||
|
# s/$/\"/g
|
||||||
|
# }
|
||||||
|
}"
|
||||||
|
|
||||||
|
|
||||||
|
# Variables:
|
||||||
|
# INI_ENV_PREFIX="INI_"
|
||||||
|
# INI_GLOBAL_??="GLOBAL"
|
||||||
|
# INI_SECTION_??="SECTION"
|
||||||
|
# Options:
|
||||||
|
#
|
||||||
|
|
||||||
|
exit
|
||||||
|
|
||||||
|
/^[[:blank:]]*\[.*\]/ {
|
||||||
|
s/[[:blank:]]*\[/)\n/g
|
||||||
|
# s/(.*)\]/declare -A ${VAR}_\1=(/g
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-e "/^[[:blank:]]*\[.*\]/ s/[[:blank:]]*\[/)\n/g; s/(.*)\]/declare -A ${VAR}_\1=(/g"
|
||||||
|
|
||||||
|
-e 's/^[[:blank:]]*\</[
|
||||||
|
|
||||||
|
|
||||||
|
sed -r \
|
||||||
|
-e '/^[[:blank:]]*(#|;|$)/ d' \
|
||||||
|
-e "1 ideclare -A ${VAR}_${TOP}=(" \
|
||||||
|
-e "/^[[:blank:]]*\[.*\]/ s/[[:blank:]]*\[/)\n/g; s/(.*)\]/declare -A ${VAR}_\1=(/g"
|
||||||
|
|
||||||
|
-e 's/^[[:blank:]]*\</[
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-e "1 s/^/declare -A ${VAR}_${TOP}=(\n/" \
|
||||||
|
|
||||||
|
# if a line ends with a backslash, append the next line to it
|
||||||
|
sed -e :a -e '/\\$/N; s/\\\n//; ta'
|
||||||
|
|
||||||
|
# print the line immediately before a regexp, but not the line
|
||||||
|
# containing the regexp
|
||||||
|
sed -n '/regexp/{g;1!p;};h'
|
||||||
|
|
||||||
|
# print the line immediately after a regexp, but not the line
|
||||||
|
# containing the regexp
|
||||||
|
sed -n '/regexp/{n;p;}'
|
||||||
|
|
||||||
|
# print section of file from regular expression to end of file
|
||||||
|
sed -n '/regexp/,$p'
|
||||||
|
|
||||||
|
# print section of file between two regular expressions (inclusive)
|
||||||
|
sed -n '/Iowa/,/Montana/p' # case sensitive
|
||||||
|
|
||||||
|
|
||||||
|
# Option (-r) to make all variables read only.
|
||||||
|
# Option (-x) to export all variables.
|
||||||
|
|
||||||
|
# Option parsing.
|
||||||
|
# http://mywiki.wooledge.org/BashFAQ/035
|
||||||
|
|
||||||
123
bits/sed-parser/sed-parser.broken-merge
Normal file
123
bits/sed-parser/sed-parser.broken-merge
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Todo:
|
||||||
|
# Change case of variables: \L \U \E
|
||||||
|
# export SECLIST="SECTIONS"
|
||||||
|
export VARPREFIX="INI_"
|
||||||
|
export SECPREFIX="SECTION_"
|
||||||
|
export SECCNAMEKEY="%cannonical name%"
|
||||||
|
export TOPSEC="global"
|
||||||
|
initest() {
|
||||||
|
echo "declare -A ${VARPREFIX}${SECPREFIX}${TOPSEC}"
|
||||||
|
echo "${VARPREFIX}${SECPREFIX}${TOPSEC}[${SECCNAMEKEY}]=\"${TOPSEC}\""
|
||||||
|
cat test.ini | sed -r "{
|
||||||
|
/^[[:blank:]]*(#|;|$)/ d
|
||||||
|
/^[[:blank:]]*\[.*\][[:blank:]]*$/ {
|
||||||
|
s/(^[[:blank:]]*\[[[:blank:]]*|[[:blank:]]*\][[:blank:]]*$)//g ; h
|
||||||
|
s/([[:blank:]]+|[^[:alnum:]])/_/g
|
||||||
|
s/(.*)/declare -A ${VARPREFIX}${SECPREFIX}\1\n${VARPREFIX}${SECPREFIX}\1/ ; P ; g
|
||||||
|
s/(.*)/\[${SECCNAMEKEY}\]=\"\1\"/
|
||||||
|
}
|
||||||
|
/^[[:blank:]]*[[:print:]]+[[:blank:]][=:]/ {
|
||||||
|
d
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
}
|
||||||
|
|
||||||
|
; initest
|
||||||
|
|
||||||
|
|
||||||
|
[ [ invalid-section###3 ] $$ ] $
|
||||||
|
[ invalid-section###3 ] $$X
|
||||||
|
# Squash multiple blanks and invalid chars to single _ -- s/[^[:alnum:]]+/_/g
|
||||||
|
_invalid_section_3_
|
||||||
|
# Blanks and invalid chars replaced with _ no sqash -- s/[^[:alnum:]]/_/g
|
||||||
|
_________invalid_section___3_______
|
||||||
|
# Squash multiple blanks to single _ and replace invalid chars with _ -- s/([[:blank:]]+|[^[:alnum:]])/_/g
|
||||||
|
__invalid_section___3_____
|
||||||
|
|
||||||
|
|
||||||
|
#s/[[:blank:]]*\][[:blank:]]*[^[:alnum:]]+/_/g
|
||||||
|
# s/^[[:blank:]]*\[[[:blank:]]*/declare -A ${VAR}_/
|
||||||
|
# s/[[:blank:]]*\][[:blank:]]*$/=(/
|
||||||
|
|
||||||
|
# s/(^[[:blank:]]*\[[[:blank:]]*)|([[:blank:]]*\][[:blank:]]*$)/X/g
|
||||||
|
# s/[[:blank:]]+/ /g
|
||||||
|
# s/^[[:blank:]]*\[[[:blank:]]*([[:graph:]]*)[[:blank:]]*\][[:blank:]]*$/[\1]/
|
||||||
|
l 120
|
||||||
|
# s/^[[:blank:]]*(\[|\]) [[:blank:]]*$/\1/g
|
||||||
|
# s/([^[:alnum:]]|_+)/_/g
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
|
||||||
|
s/[[:blank:]]*(\[|\])[[:blank:]]*/\1/g
|
||||||
|
s/([^[:alnum:]]|_+)/_/g
|
||||||
|
|
||||||
|
|
||||||
|
label regex jump back if s was done
|
||||||
|
|
||||||
|
|
||||||
|
# s/\[_*([^]]*)/declare -A ${VAR}_\1=(/
|
||||||
|
# s/\[_*(.*)_*\].*/declare -A ${VAR}_\1=(/
|
||||||
|
# s/[[:blank:]]*\[(.*)\].*/declare -A ${VAR}_\1=(/
|
||||||
|
}
|
||||||
|
# /^(\)|declare -A)/ ! {
|
||||||
|
# s/^[[:blank:]]*/\[/
|
||||||
|
# s/[[:blank:]]*=[[:blank:]]*/\]=\"/
|
||||||
|
# s/$/\"/g
|
||||||
|
# }
|
||||||
|
}"
|
||||||
|
|
||||||
|
|
||||||
|
# Variables:
|
||||||
|
# INI_ENV_PREFIX="INI_"
|
||||||
|
# INI_GLOBAL_??="GLOBAL"
|
||||||
|
# INI_SECTION_??="SECTION"
|
||||||
|
# Options:
|
||||||
|
#
|
||||||
|
|
||||||
|
exit
|
||||||
|
|
||||||
|
/^[[:blank:]]*\[.*\]/ {
|
||||||
|
s/[[:blank:]]*\[/)\n/g
|
||||||
|
# s/(.*)\]/declare -A ${VAR}_\1=(/g
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-e "/^[[:blank:]]*\[.*\]/ s/[[:blank:]]*\[/)\n/g; s/(.*)\]/declare -A ${VAR}_\1=(/g"
|
||||||
|
|
||||||
|
-e 's/^[[:blank:]]*\</[
|
||||||
|
|
||||||
|
|
||||||
|
sed -r \
|
||||||
|
-e '/^[[:blank:]]*(#|;|$)/ d' \
|
||||||
|
-e "1 ideclare -A ${VAR}_${TOP}=(" \
|
||||||
|
-e "/^[[:blank:]]*\[.*\]/ s/[[:blank:]]*\[/)\n/g; s/(.*)\]/declare -A ${VAR}_\1=(/g"
|
||||||
|
|
||||||
|
-e 's/^[[:blank:]]*\</[
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-e "1 s/^/declare -A ${VAR}_${TOP}=(\n/" \
|
||||||
|
|
||||||
|
# if a line ends with a backslash, append the next line to it
|
||||||
|
sed -e :a -e '/\\$/N; s/\\\n//; ta'
|
||||||
|
|
||||||
|
# print the line immediately before a regexp, but not the line
|
||||||
|
# containing the regexp
|
||||||
|
sed -n '/regexp/{g;1!p;};h'
|
||||||
|
|
||||||
|
# print the line immediately after a regexp, but not the line
|
||||||
|
# containing the regexp
|
||||||
|
sed -n '/regexp/{n;p;}'
|
||||||
|
|
||||||
|
# print section of file from regular expression to end of file
|
||||||
|
sed -n '/regexp/,$p'
|
||||||
|
|
||||||
|
# print section of file between two regular expressions (inclusive)
|
||||||
|
sed -n '/Iowa/,/Montana/p' # case sensitive
|
||||||
|
|
||||||
|
|
||||||
|
# Option (-r) to make all variables read only.
|
||||||
|
# Option (-x) to export all variables.
|
||||||
128
bits/sed-parser/sed-parser.duplicates
Normal file
128
bits/sed-parser/sed-parser.duplicates
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Todo:
|
||||||
|
# Change case of variables: \L \U \E
|
||||||
|
# export SECLIST="SECTIONS"
|
||||||
|
export VARPREFIX="INI_"
|
||||||
|
export SECPREFIX="SECTION_"
|
||||||
|
export SECCNAMEKEY="%cannonical name%"
|
||||||
|
export TOPSEC="global"
|
||||||
|
initest() {
|
||||||
|
echo "declare -A ${VARPREFIX}${SECPREFIX}${TOPSEC}"
|
||||||
|
echo "${VARPREFIX}${SECPREFIX}${TOPSEC}+=("
|
||||||
|
echo "[${SECCNAMEKEY}]=\"${TOPSEC}\""
|
||||||
|
cat test.ini | sed -r "{
|
||||||
|
/^[[:blank:]]*(#|;|$)/ d
|
||||||
|
/^[[:blank:]]*\[.*\][[:blank:]]*$/ {
|
||||||
|
i )
|
||||||
|
s/(^[[:blank:]]*\[[[:blank:]]*|[[:blank:]]*\][[:blank:]]*$)//g
|
||||||
|
h
|
||||||
|
s/([[:blank:]]+|[^[:alnum:]])/_/g
|
||||||
|
s/(.*)/declare -A ${VARPREFIX}${SECPREFIX}\1\n${VARPREFIX}${SECPREFIX}\1+=(/
|
||||||
|
p ; g
|
||||||
|
s/(.*)/\[${SECCNAMEKEY}\]=\"\1\"/
|
||||||
|
}
|
||||||
|
/^[[:blank:]]*[[:print:]]+[[:blank:]][=:]/ {
|
||||||
|
d
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
echo ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
; initest
|
||||||
|
|
||||||
|
|
||||||
|
[ [ invalid-section###3 ] $$ ] $
|
||||||
|
[ invalid-section###3 ] $$X
|
||||||
|
# Squash multiple blanks and invalid chars to single _ -- s/[^[:alnum:]]+/_/g
|
||||||
|
_invalid_section_3_
|
||||||
|
# Blanks and invalid chars replaced with _ no sqash -- s/[^[:alnum:]]/_/g
|
||||||
|
_________invalid_section___3_______
|
||||||
|
# Squash multiple blanks to single _ and replace invalid chars with _ -- s/([[:blank:]]+|[^[:alnum:]])/_/g
|
||||||
|
__invalid_section___3_____
|
||||||
|
|
||||||
|
|
||||||
|
#s/[[:blank:]]*\][[:blank:]]*[^[:alnum:]]+/_/g
|
||||||
|
# s/^[[:blank:]]*\[[[:blank:]]*/declare -A ${VAR}_/
|
||||||
|
# s/[[:blank:]]*\][[:blank:]]*$/=(/
|
||||||
|
|
||||||
|
# s/(^[[:blank:]]*\[[[:blank:]]*)|([[:blank:]]*\][[:blank:]]*$)/X/g
|
||||||
|
# s/[[:blank:]]+/ /g
|
||||||
|
# s/^[[:blank:]]*\[[[:blank:]]*([[:graph:]]*)[[:blank:]]*\][[:blank:]]*$/[\1]/
|
||||||
|
l 120
|
||||||
|
# s/^[[:blank:]]*(\[|\]) [[:blank:]]*$/\1/g
|
||||||
|
# s/([^[:alnum:]]|_+)/_/g
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
|
||||||
|
s/[[:blank:]]*(\[|\])[[:blank:]]*/\1/g
|
||||||
|
s/([^[:alnum:]]|_+)/_/g
|
||||||
|
|
||||||
|
|
||||||
|
label regex jump back if s was done
|
||||||
|
|
||||||
|
|
||||||
|
# s/\[_*([^]]*)/declare -A ${VAR}_\1=(/
|
||||||
|
# s/\[_*(.*)_*\].*/declare -A ${VAR}_\1=(/
|
||||||
|
# s/[[:blank:]]*\[(.*)\].*/declare -A ${VAR}_\1=(/
|
||||||
|
}
|
||||||
|
# /^(\)|declare -A)/ ! {
|
||||||
|
# s/^[[:blank:]]*/\[/
|
||||||
|
# s/[[:blank:]]*=[[:blank:]]*/\]=\"/
|
||||||
|
# s/$/\"/g
|
||||||
|
# }
|
||||||
|
}"
|
||||||
|
|
||||||
|
|
||||||
|
# Variables:
|
||||||
|
# INI_ENV_PREFIX="INI_"
|
||||||
|
# INI_GLOBAL_??="GLOBAL"
|
||||||
|
# INI_SECTION_??="SECTION"
|
||||||
|
# Options:
|
||||||
|
#
|
||||||
|
|
||||||
|
exit
|
||||||
|
|
||||||
|
/^[[:blank:]]*\[.*\]/ {
|
||||||
|
s/[[:blank:]]*\[/)\n/g
|
||||||
|
# s/(.*)\]/declare -A ${VAR}_\1=(/g
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-e "/^[[:blank:]]*\[.*\]/ s/[[:blank:]]*\[/)\n/g; s/(.*)\]/declare -A ${VAR}_\1=(/g"
|
||||||
|
|
||||||
|
-e 's/^[[:blank:]]*\</[
|
||||||
|
|
||||||
|
|
||||||
|
sed -r \
|
||||||
|
-e '/^[[:blank:]]*(#|;|$)/ d' \
|
||||||
|
-e "1 ideclare -A ${VAR}_${TOP}=(" \
|
||||||
|
-e "/^[[:blank:]]*\[.*\]/ s/[[:blank:]]*\[/)\n/g; s/(.*)\]/declare -A ${VAR}_\1=(/g"
|
||||||
|
|
||||||
|
-e 's/^[[:blank:]]*\</[
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-e "1 s/^/declare -A ${VAR}_${TOP}=(\n/" \
|
||||||
|
|
||||||
|
# if a line ends with a backslash, append the next line to it
|
||||||
|
sed -e :a -e '/\\$/N; s/\\\n//; ta'
|
||||||
|
|
||||||
|
# print the line immediately before a regexp, but not the line
|
||||||
|
# containing the regexp
|
||||||
|
sed -n '/regexp/{g;1!p;};h'
|
||||||
|
|
||||||
|
# print the line immediately after a regexp, but not the line
|
||||||
|
# containing the regexp
|
||||||
|
sed -n '/regexp/{n;p;}'
|
||||||
|
|
||||||
|
# print section of file from regular expression to end of file
|
||||||
|
sed -n '/regexp/,$p'
|
||||||
|
|
||||||
|
# print section of file between two regular expressions (inclusive)
|
||||||
|
sed -n '/Iowa/,/Montana/p' # case sensitive
|
||||||
|
|
||||||
|
|
||||||
|
# Option (-r) to make all variables read only.
|
||||||
|
# Option (-x) to export all variables.
|
||||||
117
bits/sed-parser/sed-parser.nofunc
Normal file
117
bits/sed-parser/sed-parser.nofunc
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export VARPREFIX="INI_"
|
||||||
|
export SECPREFIX="SECTION_"
|
||||||
|
export SECLIST="SECTIONS"
|
||||||
|
export TOPSEC="global"
|
||||||
|
|
||||||
|
cat test.ini | sed -r "{
|
||||||
|
1 i declare -a ${VARPREFIX}${SECLIST}=( ${VARPREFIX}${SECPREFIX}${TOPSEC} )
|
||||||
|
1 i declare -A ${VARPREFIX}${SECPREFIX}${TOPSEC}=(
|
||||||
|
$ a )
|
||||||
|
/^[[:blank:]]*(#|;|$)/ d
|
||||||
|
/^[[:blank:]]*\[.*\][[:blank:]]*$/ {
|
||||||
|
i )
|
||||||
|
s/(^[[:blank:]]*\[[[:blank:]]*|[[:blank:]]*\][[:blank:]]*$)//g
|
||||||
|
s/([[:blank:]]+|[^[:alnum:]])/_/g
|
||||||
|
h ; s/(.*)/${VARPREFIX}${SECLIST}+=( \1 )/ ; p ; g
|
||||||
|
s/(.*)/declare -A ${VARPREFIX}${SECPREFIX}\1=(/
|
||||||
|
b
|
||||||
|
}
|
||||||
|
/.*=.*/ {
|
||||||
|
d
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
|
||||||
|
[ [ invalid-section###3 ] $$ ] $
|
||||||
|
[ invalid-section###3 ] $$X
|
||||||
|
# Squash multiple blanks and invalid chars to single _ -- s/[^[:alnum:]]+/_/g
|
||||||
|
_invalid_section_3_
|
||||||
|
# Blanks and invalid chars replaced with _ no sqash -- s/[^[:alnum:]]/_/g
|
||||||
|
_________invalid_section___3_______
|
||||||
|
# Squash multiple blanks to single _ and replace invalid chars with _ -- s/([[:blank:]]+|[^[:alnum:]])/_/g
|
||||||
|
__invalid_section___3_____
|
||||||
|
|
||||||
|
|
||||||
|
#s/[[:blank:]]*\][[:blank:]]*[^[:alnum:]]+/_/g
|
||||||
|
# s/^[[:blank:]]*\[[[:blank:]]*/declare -A ${VAR}_/
|
||||||
|
# s/[[:blank:]]*\][[:blank:]]*$/=(/
|
||||||
|
|
||||||
|
# s/(^[[:blank:]]*\[[[:blank:]]*)|([[:blank:]]*\][[:blank:]]*$)/X/g
|
||||||
|
# s/[[:blank:]]+/ /g
|
||||||
|
# s/^[[:blank:]]*\[[[:blank:]]*([[:graph:]]*)[[:blank:]]*\][[:blank:]]*$/[\1]/
|
||||||
|
l 120
|
||||||
|
# s/^[[:blank:]]*(\[|\]) [[:blank:]]*$/\1/g
|
||||||
|
# s/([^[:alnum:]]|_+)/_/g
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
|
||||||
|
s/[[:blank:]]*(\[|\])[[:blank:]]*/\1/g
|
||||||
|
s/([^[:alnum:]]|_+)/_/g
|
||||||
|
|
||||||
|
|
||||||
|
label regex jump back if s was done
|
||||||
|
|
||||||
|
|
||||||
|
# s/\[_*([^]]*)/declare -A ${VAR}_\1=(/
|
||||||
|
# s/\[_*(.*)_*\].*/declare -A ${VAR}_\1=(/
|
||||||
|
# s/[[:blank:]]*\[(.*)\].*/declare -A ${VAR}_\1=(/
|
||||||
|
}
|
||||||
|
# /^(\)|declare -A)/ ! {
|
||||||
|
# s/^[[:blank:]]*/\[/
|
||||||
|
# s/[[:blank:]]*=[[:blank:]]*/\]=\"/
|
||||||
|
# s/$/\"/g
|
||||||
|
# }
|
||||||
|
}"
|
||||||
|
|
||||||
|
|
||||||
|
# Variables:
|
||||||
|
# INI_ENV_PREFIX="INI_"
|
||||||
|
# INI_GLOBAL_??="GLOBAL"
|
||||||
|
# INI_SECTION_??="SECTION"
|
||||||
|
# Options:
|
||||||
|
#
|
||||||
|
|
||||||
|
exit
|
||||||
|
|
||||||
|
/^[[:blank:]]*\[.*\]/ {
|
||||||
|
s/[[:blank:]]*\[/)\n/g
|
||||||
|
# s/(.*)\]/declare -A ${VAR}_\1=(/g
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-e "/^[[:blank:]]*\[.*\]/ s/[[:blank:]]*\[/)\n/g; s/(.*)\]/declare -A ${VAR}_\1=(/g"
|
||||||
|
|
||||||
|
-e 's/^[[:blank:]]*\</[
|
||||||
|
|
||||||
|
|
||||||
|
sed -r \
|
||||||
|
-e '/^[[:blank:]]*(#|;|$)/ d' \
|
||||||
|
-e "1 ideclare -A ${VAR}_${TOP}=(" \
|
||||||
|
-e "/^[[:blank:]]*\[.*\]/ s/[[:blank:]]*\[/)\n/g; s/(.*)\]/declare -A ${VAR}_\1=(/g"
|
||||||
|
|
||||||
|
-e 's/^[[:blank:]]*\</[
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-e "1 s/^/declare -A ${VAR}_${TOP}=(\n/" \
|
||||||
|
|
||||||
|
# if a line ends with a backslash, append the next line to it
|
||||||
|
sed -e :a -e '/\\$/N; s/\\\n//; ta'
|
||||||
|
|
||||||
|
# print the line immediately before a regexp, but not the line
|
||||||
|
# containing the regexp
|
||||||
|
sed -n '/regexp/{g;1!p;};h'
|
||||||
|
|
||||||
|
# print the line immediately after a regexp, but not the line
|
||||||
|
# containing the regexp
|
||||||
|
sed -n '/regexp/{n;p;}'
|
||||||
|
|
||||||
|
# print section of file from regular expression to end of file
|
||||||
|
sed -n '/regexp/,$p'
|
||||||
|
|
||||||
|
# print section of file between two regular expressions (inclusive)
|
||||||
|
sed -n '/Iowa/,/Montana/p' # case sensitive
|
||||||
|
|
||||||
|
|
||||||
185
bits/sed-parser/sed-parser.sh
Normal file
185
bits/sed-parser/sed-parser.sh
Normal file
|
|
@ -0,0 +1,185 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Notes:
|
||||||
|
# Cannot use any of the deliminators in the key name
|
||||||
|
# Todo:
|
||||||
|
# Lines beginning with #; within " .. " blocks on new lines will be stripped.
|
||||||
|
# Allow merging of multiple sections with the same name
|
||||||
|
# Change case of variables: \L \U \E
|
||||||
|
# export SECLIST="SECTIONS"
|
||||||
|
# Allow delims to be specified in a var - don't assume =:
|
||||||
|
|
||||||
|
export VARPREFIX="INI_"
|
||||||
|
export SECPREFIX="SECTION_"
|
||||||
|
export SECCNAMEKEY="%cannonical name%"
|
||||||
|
export TOPSEC="global"
|
||||||
|
initest() {
|
||||||
|
echo "declare -A ${VARPREFIX}${SECPREFIX}${TOPSEC}=("
|
||||||
|
echo "[${SECCNAMEKEY}]=\"${TOPSEC}\""
|
||||||
|
cat $1 | sed -r "{
|
||||||
|
# Ignore blank lines and comments
|
||||||
|
/^[[:blank:]]*(#|;|$)/ d
|
||||||
|
# Handle [section] lines
|
||||||
|
/^[[:blank:]]*\[.*\][[:blank:]]*$/ {
|
||||||
|
i )
|
||||||
|
s/(^[[:blank:]]*\[[[:blank:]]*|[[:blank:]]*\][[:blank:]]*$)//g
|
||||||
|
h
|
||||||
|
s/([[:blank:]]+|[^[:alnum:]])/_/g
|
||||||
|
s/(.*)/declare -A ${VARPREFIX}${SECPREFIX}\1=(/p
|
||||||
|
g
|
||||||
|
s/(.*)/ \[${SECCNAMEKEY}\]=\"\1\"/
|
||||||
|
b
|
||||||
|
}
|
||||||
|
# FIXME: This needs to pick up escaped =:s
|
||||||
|
/^([[:blank:]]*[^[:blank:]]+[[:blank:]]*)+[=:].*$/ {
|
||||||
|
# Escape any ] characters within key name - bash <4.3 can't handle them
|
||||||
|
s/^(([^\]]*)\[+)*([=:].*)$/\2\\\\\]\3/
|
||||||
|
# Escape any ' characters within the key name
|
||||||
|
s/^[[:blank:]]*/ \[\'/
|
||||||
|
s/[[:blank:]]*[=:][[:blank:]]*(.*)$/\']=\1/
|
||||||
|
########s/([\"]+)/\\\\\1/g
|
||||||
|
#s/^(\[')([']+)('\].*)/\1X\3/g
|
||||||
|
# s/[[:blank:]]*[=:][[:blank:]]*[\"\'\`]?(.*)$/\]=\'\1/
|
||||||
|
# s/^[[:blank:]]*([[:print:]]+)[[:blank:]]*[=:][[:blank:]]*/\[\1\]=/
|
||||||
|
b
|
||||||
|
}
|
||||||
|
q
|
||||||
|
}"
|
||||||
|
echo ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
; initest
|
||||||
|
|
||||||
|
# Join lines ending in \ :
|
||||||
|
sed ':x; /\\$/ { N; s/\\\n//; tx }' textfile
|
||||||
|
|
||||||
|
echo 'ao ao ao | ao' | sed 'h; s/.*|/|/; x; s/|.*//; s/o/x/g; G; s/\n//'
|
||||||
|
|
||||||
|
|
||||||
|
# if a line ends with a backslash, append the next line to it
|
||||||
|
sed -e :a -e '/\\$/N; s/\\\n//; ta'
|
||||||
|
|
||||||
|
|
||||||
|
# 4.0 needs the backslash escaped AND the ] when referencing the element
|
||||||
|
06:09 <Tadgy> 40# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}"
|
||||||
|
06:09 <shbot> declare -A FOOF='([test\\\]test]="test" )'
|
||||||
|
06:09 <shbot> <>
|
||||||
|
06:11 <Tadgy> 40# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\\\]test']}"
|
||||||
|
06:11 <shbot> declare -A FOOF='([test\\\]test]="test" )'
|
||||||
|
06:11 <shbot> <test>
|
||||||
|
|
||||||
|
# 4.1, 4.2, 4.3 are consistent with this syntax
|
||||||
|
06:06 <Tadgy> 41# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}"
|
||||||
|
06:06 <shbot> declare -A FOOF='(["test\\]test"]="test" )'
|
||||||
|
06:06 <shbot> <test>
|
||||||
|
06:08 <Tadgy> 42# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}"
|
||||||
|
06:08 <shbot> declare -A FOOF='(["test\\]test"]="test" )'
|
||||||
|
06:08 <shbot> <test>
|
||||||
|
06:09 <Tadgy> 43# declare -A FOOF=( ['test\]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test\]test']}"
|
||||||
|
06:09 <shbot> declare -A FOOF='(["test\\]test"]="test" )'
|
||||||
|
06:09 <shbot> <test>
|
||||||
|
#Works without escapes in 4.3:
|
||||||
|
06:08 <Tadgy> 43# declare -A FOOF=( ['test]test']="test" ) ; declare -p FOOF ; printf "<%s>" "${FOOF['test]test']}"
|
||||||
|
06:08 <shbot> declare -A FOOF='(["test]test"]="test" )'
|
||||||
|
06:08 <shbot> <test>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[ [ invalid-section###3 ] $$ ] $
|
||||||
|
[ invalid-section###3 ] $$X
|
||||||
|
# Squash multiple blanks and invalid chars to single _ -- s/[^[:alnum:]]+/_/g
|
||||||
|
_invalid_section_3_
|
||||||
|
# Blanks and invalid chars replaced with _ no sqash -- s/[^[:alnum:]]/_/g
|
||||||
|
_________invalid_section___3_______
|
||||||
|
# Squash multiple blanks to single _ and replace invalid chars with _ -- s/([[:blank:]]+|[^[:alnum:]])/_/g
|
||||||
|
__invalid_section___3_____
|
||||||
|
|
||||||
|
|
||||||
|
#s/[[:blank:]]*\][[:blank:]]*[^[:alnum:]]+/_/g
|
||||||
|
# s/^[[:blank:]]*\[[[:blank:]]*/declare -A ${VAR}_/
|
||||||
|
# s/[[:blank:]]*\][[:blank:]]*$/=(/
|
||||||
|
|
||||||
|
# s/(^[[:blank:]]*\[[[:blank:]]*)|([[:blank:]]*\][[:blank:]]*$)/X/g
|
||||||
|
# s/[[:blank:]]+/ /g
|
||||||
|
# s/^[[:blank:]]*\[[[:blank:]]*([[:graph:]]*)[[:blank:]]*\][[:blank:]]*$/[\1]/
|
||||||
|
l 120
|
||||||
|
# s/^[[:blank:]]*(\[|\]) [[:blank:]]*$/\1/g
|
||||||
|
# s/([^[:alnum:]]|_+)/_/g
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
|
||||||
|
s/[[:blank:]]*(\[|\])[[:blank:]]*/\1/g
|
||||||
|
s/([^[:alnum:]]|_+)/_/g
|
||||||
|
|
||||||
|
|
||||||
|
label regex jump back if s was done
|
||||||
|
|
||||||
|
|
||||||
|
# s/\[_*([^]]*)/declare -A ${VAR}_\1=(/
|
||||||
|
# s/\[_*(.*)_*\].*/declare -A ${VAR}_\1=(/
|
||||||
|
# s/[[:blank:]]*\[(.*)\].*/declare -A ${VAR}_\1=(/
|
||||||
|
}
|
||||||
|
# /^(\)|declare -A)/ ! {
|
||||||
|
# s/^[[:blank:]]*/\[/
|
||||||
|
# s/[[:blank:]]*=[[:blank:]]*/\]=\"/
|
||||||
|
# s/$/\"/g
|
||||||
|
# }
|
||||||
|
}"
|
||||||
|
|
||||||
|
|
||||||
|
# Variables:
|
||||||
|
# INI_ENV_PREFIX="INI_"
|
||||||
|
# INI_GLOBAL_??="GLOBAL"
|
||||||
|
# INI_SECTION_??="SECTION"
|
||||||
|
# Options:
|
||||||
|
#
|
||||||
|
|
||||||
|
exit
|
||||||
|
|
||||||
|
/^[[:blank:]]*\[.*\]/ {
|
||||||
|
s/[[:blank:]]*\[/)\n/g
|
||||||
|
# s/(.*)\]/declare -A ${VAR}_\1=(/g
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-e "/^[[:blank:]]*\[.*\]/ s/[[:blank:]]*\[/)\n/g; s/(.*)\]/declare -A ${VAR}_\1=(/g"
|
||||||
|
|
||||||
|
-e 's/^[[:blank:]]*\</[
|
||||||
|
|
||||||
|
|
||||||
|
sed -r \
|
||||||
|
-e '/^[[:blank:]]*(#|;|$)/ d' \
|
||||||
|
-e "1 ideclare -A ${VAR}_${TOP}=(" \
|
||||||
|
-e "/^[[:blank:]]*\[.*\]/ s/[[:blank:]]*\[/)\n/g; s/(.*)\]/declare -A ${VAR}_\1=(/g"
|
||||||
|
|
||||||
|
-e 's/^[[:blank:]]*\</[
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-e "1 s/^/declare -A ${VAR}_${TOP}=(\n/" \
|
||||||
|
|
||||||
|
# if a line ends with a backslash, append the next line to it
|
||||||
|
sed -e :a -e '/\\$/N; s/\\\n//; ta'
|
||||||
|
|
||||||
|
# print the line immediately before a regexp, but not the line
|
||||||
|
# containing the regexp
|
||||||
|
sed -n '/regexp/{g;1!p;};h'
|
||||||
|
|
||||||
|
# print the line immediately after a regexp, but not the line
|
||||||
|
# containing the regexp
|
||||||
|
sed -n '/regexp/{n;p;}'
|
||||||
|
|
||||||
|
# print section of file from regular expression to end of file
|
||||||
|
sed -n '/regexp/,$p'
|
||||||
|
|
||||||
|
# print section of file between two regular expressions (inclusive)
|
||||||
|
sed -n '/Iowa/,/Montana/p' # case sensitive
|
||||||
|
|
||||||
|
|
||||||
|
# Option (-r) to make all variables read only.
|
||||||
|
# Option (-x) to export all variables.
|
||||||
|
|
||||||
|
# Option parsing.
|
||||||
|
# http://mywiki.wooledge.org/BashFAQ/035
|
||||||
|
|
||||||
41
bits/value-tests.ini
Normal file
41
bits/value-tests.ini
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
#####################
|
||||||
|
# Single line tests #
|
||||||
|
#####################
|
||||||
|
|
||||||
|
# No quotes, extra spaces within value.
|
||||||
|
key name 1 = key value 1
|
||||||
|
|
||||||
|
# No quotes, tab+spaces before value.
|
||||||
|
key name 2 = key value 2
|
||||||
|
|
||||||
|
# No quotes, spaces before and after value.
|
||||||
|
key name 3 = key value 3
|
||||||
|
|
||||||
|
# No quotes, extra spacing before and after value, value includes "
|
||||||
|
key name 4 =
|
||||||
|
|
||||||
|
# Double quotes, extra spaces within value.
|
||||||
|
key name 4 = "this is a line with many spaces in it"
|
||||||
|
|
||||||
|
# Single quotes, extra spaces within value.
|
||||||
|
key name 5 = 'extra spaces within value'
|
||||||
|
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
####################
|
||||||
|
# Multi line tests #
|
||||||
|
####################
|
||||||
|
|
||||||
|
key name 5 = ' this is a multiple
|
||||||
|
line entry'
|
||||||
|
|
||||||
|
key name 6 = this is a second \
|
||||||
|
multi \
|
||||||
|
line entry
|
||||||
|
|
||||||
|
key name 7 = "\
|
||||||
|
this should
|
||||||
|
all be aligned left"
|
||||||
284
parse_ini
Executable file
284
parse_ini
Executable file
|
|
@ -0,0 +1,284 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# http://en.wikipedia.org/wiki/INI_file:
|
||||||
|
# * Provides a good explanation of the ini format - use this for docs *
|
||||||
|
# * INI's have 'sections' and 'properties'. Properties have key = value format *
|
||||||
|
#
|
||||||
|
# Case insensitivity: Add a case sensitive option
|
||||||
|
# Comments: Allow ; and # for comments. Must be on their own line
|
||||||
|
# Blank lines: Allow blank lines always
|
||||||
|
# Duplicate names: Duplicate property values overwrite previous values.
|
||||||
|
# Provide an option to abort/error is duplicate is found?
|
||||||
|
# Add option to merge duplicates separated by octal byte (\036 ??)
|
||||||
|
# Duplicate sections are merged. Option to error if dup.
|
||||||
|
# Escape chars: Handled by bash directly. Allow \ to continue a line.
|
||||||
|
# Global properties: Support. Add to a GLOBAL section?
|
||||||
|
# Hierarchy: No hierarchy support. Each section is own section.
|
||||||
|
# Name/value delim: Use = by default. Allow : via option?
|
||||||
|
# Quoted values: Allow values to be within " and ' to keep literal formatting.
|
||||||
|
# Whitespace: Whitespace around section labels and []s is removed.
|
||||||
|
# Whitespace within section labels is kept / translated.
|
||||||
|
# Whitespace around property names is removed.
|
||||||
|
# Whitespace within property names is kept as is (spaces squashed - option to override).
|
||||||
|
# Property values have whitespace between = and data removed.
|
||||||
|
# Property values are kept as is (no squashing)
|
||||||
|
# Ordering: GLOBAL section must be at the top, sections continue until next section or EOF.
|
||||||
|
|
||||||
|
# http://www.regular-expressions.info/posixbrackets.html
|
||||||
|
# http://ajdiaz.wordpress.com/2008/02/09/bash-ini-parser/
|
||||||
|
# https://github.com/rudimeier/bash_ini_parser/blob/ff9d46a5503bf41b3344af85447e28cbaf95350e/read_ini.sh
|
||||||
|
# http://tldp.org/LDP/abs/html/
|
||||||
|
# Specs:
|
||||||
|
# [section] Can be upper/lower/mixed case (set by options)
|
||||||
|
# Can only include: '-+_. [:alnum:]'
|
||||||
|
# Any single or consecutive occurance of '-+_. ' are converted to a *single* _
|
||||||
|
# eg: [foo -+_. bar] becomes [foo_bar] ??
|
||||||
|
# Any leading/trailing spaces/tabs between the []s and name will be removed.
|
||||||
|
|
||||||
|
|
||||||
|
# Notes:
|
||||||
|
# * To make env vars available to subsequent programs, use -x|--export.
|
||||||
|
|
||||||
|
|
||||||
|
parser_help() {
|
||||||
|
#........1.........2.........3.........4.........5.........6.........7.........8.........9.........0.........1.........2.........3.........4.........5
|
||||||
|
cat <<EOF
|
||||||
|
Usage: ${0##*/} [options] <inifile>
|
||||||
|
Parse an ini file into environment variables which can be used natively in Bash.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-e <varname>, --envvar=<varname>
|
||||||
|
The prefix of the environment variables set by the parser.
|
||||||
|
The default is 'INI'.
|
||||||
|
-d <char(s)>, --envdelim=<char(s)>
|
||||||
|
The character(s) to use as a deliminator between the environment variable
|
||||||
|
and the section name. This is used when creating the environment
|
||||||
|
variables which hold options belonging to a particular section of the ini
|
||||||
|
file. Only letters, numbers and underscores (_) may be used. To use no
|
||||||
|
deliminator at all, use -d '' or --envdelim=''.
|
||||||
|
The default deliminator is a single underscore '_' ???
|
||||||
|
-i, --implied-boolean
|
||||||
|
Options usually require a parameter (after the =) in order to be set.
|
||||||
|
With this option, any option without a parameter contained in the ini file
|
||||||
|
if assumed to be a boolean 'true' and set accordingly. Likewise, any option
|
||||||
|
preceeded with 'no_' (eg: no_foo) will set the option 'foo' to boolean 'false'.
|
||||||
|
Cannot be used with --no-boolean.
|
||||||
|
-c, --case-sensitive
|
||||||
|
Be case sensitive with section names and properties.
|
||||||
|
Section names and property names will be used as is - no translation.
|
||||||
|
-g, --global-name <name>
|
||||||
|
INI files can contain an optional implied "global" section - where there
|
||||||
|
are property names/values before any [section] header. This option
|
||||||
|
specified what section name the implied "global" section should be given
|
||||||
|
in the environment variables which are set. The default is 'GLOBAL'.
|
||||||
|
|
||||||
|
-l, --lowercase
|
||||||
|
Usually, environment variables are converted to all uppercase before being set.
|
||||||
|
This option forces all environment variables to be converted to lowercase instead.
|
||||||
|
Note: This only effects the environment variable set with -e, and the section names
|
||||||
|
read from the ini file. Options are ??????????????????????????????????????
|
||||||
|
-x, --export
|
||||||
|
Export environment variables.
|
||||||
|
|
||||||
|
--no-boolean
|
||||||
|
Don't parse 'yes', 'true', 'on', 'no', 'false', 'off' into the corresponding boolean
|
||||||
|
values, and set the options strictly as is. Incompatible with -i.
|
||||||
|
--no-squash
|
||||||
|
Do not squash multiple consecutive occurances of punctuation characters
|
||||||
|
into a single _ when parsing section names and options. With this option
|
||||||
|
'foo.-_bar' would become 'foo___bar' rather than 'foo_bar'.
|
||||||
|
--no-duplicates
|
||||||
|
If a duplicate section name or option name is found, report error and stop.
|
||||||
|
Usually sections with the same name will have their options merged, and
|
||||||
|
duplicate option values will overwrite previous ones.
|
||||||
|
|
||||||
|
|
||||||
|
--test
|
||||||
|
Test/validate the ini file by running it through the parser. Testing the
|
||||||
|
ini file will report any problems or syntax errors in the file, but will
|
||||||
|
not set up the environment variables as would happen in normal parsing.
|
||||||
|
Any parse errors are reported to stderr. When combined with the --debug
|
||||||
|
option, every detail of the parsing process is reported to stderr.
|
||||||
|
--debug
|
||||||
|
Show full details of the ini file parsing process. Detail is written to
|
||||||
|
stderr. Unless --test is used with this option, the parser will still
|
||||||
|
set up the environment as would happen normally,
|
||||||
|
-h, --help
|
||||||
|
Show (this) help.
|
||||||
|
-v, --version
|
||||||
|
Show version and copyright information.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
parser_version() {
|
||||||
|
#........1.........2.........3.........4.........5.........6.........7.........8.........9.........0.........1.........2.........3.........4.........5
|
||||||
|
cat <<-EOF
|
||||||
|
Bash INI file parser v0.1.0.
|
||||||
|
Copyright (C) 2019 Darren 'Tadgy' Austin <darren (at) afterdark.org.uk>.
|
||||||
|
Licensed under the terms of the GNU General Public Licence version 3.
|
||||||
|
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY. For details and a full copy of
|
||||||
|
the license terms, see: <http://gnu.org/licenses/gpl.html>. This is free
|
||||||
|
software - you can modify and redistribute it under the terms of the GPL v3.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
parse_ini() {
|
||||||
|
# Bash v4.1+ is required.
|
||||||
|
if [[ -z "${BASH_VERSINFO[0]}" ]] || ((BASH_VERSINFO[0] < 4)) || ((BASH_VERSINFO[1] < 1)); then
|
||||||
|
echo "${0##*/}: minimum of bash v4.1 required" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set defaults.
|
||||||
|
local PARSER_ENV_PREFIX="INI"
|
||||||
|
local PARSER_ENV_DELIM="_"
|
||||||
|
local PARSER_ALPHA_CLASS="[:alnum:]" # All alphanumeric characters.
|
||||||
|
local PARSER_PUNCT_CLASS="-+_. !\"£\$%^&*()="$'\t' # Characters that are converted to _ in [section] names.
|
||||||
|
!"£$%^&*()-_=+{}'@#~\|,<.>/?
|
||||||
|
# TEMP:
|
||||||
|
local PARSER_INIFILE="test.ini"
|
||||||
|
|
||||||
|
|
||||||
|
parser_getopts() {
|
||||||
|
while [ ! -z "$1" ]; do
|
||||||
|
case "$1" in
|
||||||
|
-h|-help|--help)
|
||||||
|
parser_help
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
-v|-version|--version)
|
||||||
|
parser_version
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
# Stop option processing.
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
-*|--*)
|
||||||
|
echo "${0##*/}: invalid option: $1"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
# parser_getopts "$@" || return 1
|
||||||
|
|
||||||
|
# File accessability checks
|
||||||
|
if [ ! -e "$PARSER_INIFILE" ]; then
|
||||||
|
echo "${0##*/}: $PARSER_INIFILE: no such file"
|
||||||
|
return 1
|
||||||
|
elif [ ! -f "$PARSER_INIFILE" ]; then
|
||||||
|
echo "${0##*/}: $PARSER_INIFILE: not a regular file"
|
||||||
|
return 1
|
||||||
|
elif [ ! -r "$PARSER_INIFILE" ]; then
|
||||||
|
echo "${0##*/}: $PARSER_INIFILE: permission denied"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Open the ini file for reading
|
||||||
|
if ! exec {PARSER_INIFD}<"$PARSER_INIFILE"; then
|
||||||
|
echo "${0##*/}: $PARSER_INIFILE: failed to open"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# FIXME: Need to handle this properly:
|
||||||
|
shopt -s extglob
|
||||||
|
|
||||||
|
# Parse the ini file
|
||||||
|
local IFS=$'\n' PARSER_READLINE PARSER_READLINENO=0 REPLY
|
||||||
|
# local PARSER_CURSEC
|
||||||
|
while :; do
|
||||||
|
while :; do
|
||||||
|
# Read a line of input from the file descriptor
|
||||||
|
read -r -u $PARSER_INIFD || break
|
||||||
|
((PARSER_READLINENO++))
|
||||||
|
|
||||||
|
# Skip any blank/empty or comment lines
|
||||||
|
[[ "$REPLY" =~ ^[[:blank:]]*([#;].*)*$ ]] && continue
|
||||||
|
|
||||||
|
for ((I = 1; I < ${#REPLY}; I++)); do
|
||||||
|
if [[ "${REPLY: -$I:1}" =~ [[:space:]] ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# If line ends in \, save the line and read next.
|
||||||
|
# if [[ "${REPLY:-1:1}" =~ "\" ]]
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
printf "<%s>\n" "$PARSER_READLINE"
|
||||||
|
exit
|
||||||
|
|
||||||
|
# Strip any leading whitespace from the line
|
||||||
|
# Not required here,
|
||||||
|
# PARSER_READLINE="${PARSER_READLINE/#+([[:space:]])/}"
|
||||||
|
|
||||||
|
# Is this a section header?
|
||||||
|
if [ "${PARSER_READLINE:0:1}" = "[" ]; then
|
||||||
|
if [[ "$PARSER_READLINE" =~ ^\[[$PARSER_PUNCT_CLASS$PARSER_ALPHA_CLASS]+\]$ ]]; then
|
||||||
|
# Strip the []s and any leading/trailing whitespace.
|
||||||
|
# FIXME: Allow leaving the leading/trailing whitespace in place with option?
|
||||||
|
PARSER_READLINE="${PARSER_READLINE/#\[*([[:space:]])/}"
|
||||||
|
PARSER_READLINE="${PARSER_READLINE/%*([[:space:]])\]/}"
|
||||||
|
|
||||||
|
# FIXME: To convert single/consecutive punct_class into a single _ :
|
||||||
|
PARSER_READLINE="${PARSER_READLINE//+([$PARSER_PUNCT_CLASS])/_}"
|
||||||
|
# FIXME: To convert ALL occurances of punct_class into _ :
|
||||||
|
# PARSER_READLINE="${PARSER_READLINE//@([$PARSER_PUNCT_CLASS])/_}"
|
||||||
|
# FIXME: To convert single/consecutive punct_class into a single _ except for multiple _s already in line
|
||||||
|
# PARSER_READLINE="${PARSER_READLINE//+([${PARSER_PUNCT_CLASS/_//}])/_}"
|
||||||
|
|
||||||
|
# FIXME: To convert section name to uppercase:
|
||||||
|
PARSER_READLINE="${PARSER_READLINE^^}"
|
||||||
|
# FIXME: To convert section name to lowercase:
|
||||||
|
# PARSER_READLINE="${PARSER_READLINE,,}"
|
||||||
|
|
||||||
|
# Declare the associative array.
|
||||||
|
# FIXME: If doing validation only, don't declare here.
|
||||||
|
PARSER_CURSEC="$PARSER_READLINE"
|
||||||
|
declare -g -A $PARSER_ENV_PREFIX$PARSER_READLINE
|
||||||
|
|
||||||
|
set | grep $PARSER_ENV_PREFIX$PARSER_READLINE
|
||||||
|
else
|
||||||
|
echo "${0##*/}: $PARSER_INIFILE:$PARSER_READLINENO: invalid section name or format"
|
||||||
|
# FIXME: If doing validation only, continue to process - with a flag indicating every option in this
|
||||||
|
# section will be ignored if (-?) option is set.
|
||||||
|
# If (-?) option, set flag to skip all further options until reaching next section marker.
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# echo "Not header: $PARSER_READLINENO: $PARSER_READLINE"
|
||||||
|
true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# if first non-whitespace char after the first = is " or ', check the last non-whitespace char on the line.
|
||||||
|
# if that character is a matching " or ', skip to normal processing.
|
||||||
|
# if that character doesn't match the opening " or ', go to continued line processing
|
||||||
|
# else (no opening " or ') check the last non-whitespace char on the line; if its a \ (line continuation marker)
|
||||||
|
# go to continued line processing
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# Continued line processing
|
||||||
|
# Notes: If within a " or ' block, keep whitespace as entered - don't strip from begining of line.
|
||||||
|
# If here from a continueation marker, remove leading whitespace.
|
||||||
|
# Will need a flag to show if we're looking for an ending " or '
|
||||||
|
|
||||||
|
# Normal processing:
|
||||||
|
# Escape chars?
|
||||||
|
|
||||||
|
# Close file descriptor for ini file
|
||||||
|
|
||||||
|
# clean up the environment
|
||||||
|
# IFS=$INI_SAVED_IFS
|
||||||
|
# Remove any variables begining INI_
|
||||||
|
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_ini
|
||||||
Loading…
Add table
Add a link
Reference in a new issue