├── README.md └── functions.sh /README.md: -------------------------------------------------------------------------------- 1 | # bashify 2 | few helper functions in bash 3 | 4 | #repeatString 5 | repeats a string 6 | 7 | ``` bash 8 | repeatString string ?depth 9 | 10 | #depth >> how many times to repeat the string 11 | 12 | repeatString "bash" 5 # bashbashbashbashbash 13 | ``` 14 | 15 | #charAt 16 | 17 | get the position of a character in a string 18 | 19 | ```bash 20 | charAt string positionToSearch 21 | 22 | charAt "bash" 2 # a 23 | ``` 24 | 25 | #includes 26 | 27 | check if a word is in a string 28 | 29 | ```bash 30 | includes string stringToSearch ?depth 31 | 32 | #depth where to start search from 33 | 34 | includes "bash" sh 2 35 | 36 | #returns 1 for false or 0 for true 37 | ``` 38 | 39 | #endsWith 40 | check if a word is at the end of a string 41 | ```bash 42 | endsWith string endToCheck ?depth 43 | 44 | # depth >> where to start the search from 45 | 46 | endsWith "bash" a 2 47 | 48 | #returns 1 for false or 0 for true 49 | ``` 50 | 51 | #isInteger 52 | check if a value is an integer 53 | 54 | ```bash 55 | isInteger number 56 | 57 | #return 1 for non integers or 0 for integers 58 | 59 | ``` 60 | 61 | #int 62 | get all the integers before the decimal point 63 | non integers values will throw an error 64 | 65 | ```bash 66 | int number 67 | int 25.8 ; # 25 68 | ``` 69 | 70 | #destructure 71 | 72 | set the content of an array into different variables 73 | 74 | gotchas 75 | 76 | do not quote the array argument ( first agument ) 77 | 78 | it is important you quote the second argument to this function 79 | 80 | associative arrays work in alphabetical order 81 | 82 | use "," to separate the variables to assign each array element to 83 | 84 | 85 | ```bash 86 | destructure array values 87 | 88 | array=( bash ksh zsh ) 89 | 90 | destructure ${array[@]} "shell1,,shell2" 91 | 92 | echo $shell1 # bash 93 | 94 | echo $shell2 # zsh 95 | 96 | destructure ${array[@]} "shell1,shell2,shell3" 97 | 98 | echo $shell1 # bash 99 | 100 | echo $shell2 # ksh 101 | 102 | echo $shell3 # zsh 103 | 104 | ``` 105 | 106 | #... 107 | Spread a bunch of string inside an array 108 | 109 | ```bash 110 | ... string 111 | 112 | str=bash 113 | 114 | array=( $(... $str) ) 115 | 116 | echo ${str[@]} # b a s h 117 | ``` 118 | 119 | #foreach 120 | foreach element of an array execute a function 121 | 122 | gotchas: 123 | 124 | don't quote the array arugment ( i.e the first argument ) 125 | 126 | If you pass in a function as a callback using the function command you should wrap it in single quote 127 | 128 | 129 | ```bash 130 | 131 | s() { echo $(( $1 * $1 )) ;} 132 | 133 | array=( 1 2 3 4 5 6 ) 134 | 135 | foreach ${array[@]} s # 2 4 6 8 10 12 136 | 137 | foreach ${array[@]} 'function s() { echo $(( $1 + $1 )) ;}' # always end the function with a ;} 138 | # 2 4 6 8 10 12 139 | 140 | ``` 141 | 142 | 143 | #copyWithin 144 | copy an array index into another index 145 | quote the first argument use ${array[\*]} instead of ${array[@]} 146 | 147 | ```bash 148 | 149 | copyWithin arrayArgument indexToCopyfrom indexToCopyTo 150 | 151 | array=( "bash" "ksh" "zsh" "csh" ) 152 | 153 | copyWithin "${array[*]}" 1 3 # bash ksh zsh ksh 154 | 155 | ``` 156 | -------------------------------------------------------------------------------- /functions.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | true=0 3 | false=1 4 | 5 | repeatString() { 6 | local stringToRepeat="${1}" 7 | declare -i depth="${2}" 8 | 9 | if [[ -z "${stringToRepeat}" ]];then 10 | printf "%s\n" "Usage:${FUNCNAME} string ?depth" 11 | return $false 12 | fi 13 | 14 | (( depth == 0 )) && depth=1 15 | 16 | ( 17 | # depthIndex will loose it value after been executed in this subshell 18 | for ((depthIndex=0;depthIndex<${depth};depthIndex+=1)) { 19 | 20 | printf "%s" "${stringToRepeat}" 21 | 22 | } 23 | 24 | printf "\n" 25 | ) 26 | } 27 | charAt() { 28 | local char="${1}" 29 | declare -i charPosition=${2} 30 | 31 | [[ -z "${char}" ]] && \ 32 | printf "%s\n" "Usage:${FUNCNAME} string (position to extract string)" && return $false 33 | 34 | { 35 | [[ ${charPosition} -eq 0 ]] && printf "%c\n" "${char}" && return $true 36 | } || { 37 | # if the position specified is greater than the length of the string print out an empty string 38 | [[ ${charPosition} -gt ${#char} ]] && printf "%s\n" "" && return $true 39 | } 40 | 41 | 42 | 43 | ( 44 | # All the variables delcared here will get lost after this subshell finsih executing 45 | 46 | local temp=${char} 47 | local cutFirstString 48 | declare -i i=0 49 | while [[ -n "${temp}" ]];do 50 | #if [[ $charPosition == $i ]];then 51 | # printf "%c" 52 | #fi 53 | : $((i++)) 54 | cutFirstString=$(printf "%c" "${temp}") 55 | temp=${temp#*$cutFirstString} 56 | (( i == charPosition )) && printf "%s\n" "${cutFirstString}" 57 | 58 | done 59 | ) 60 | } 61 | includes() { 62 | local char="${1}" 63 | local includes="${2}" 64 | declare -i depth="${3}" 65 | { 66 | [[ -z "$char" ]] || [[ -z "$includes" ]] 67 | } && printf "%s\n" "Usage:${FUNCNAME} string includesToCheck ?depth" && return $false; 68 | if [[ $depth -gt ${#char} ]];then 69 | depth=0 70 | elif [[ $depth != 0 ]];then 71 | while [[ -n $char ]];do 72 | if [[ ! $depth -eq ${#char} ]];then 73 | char=${char#*?} 74 | continue ; 75 | fi 76 | break ; 77 | done 78 | fi 79 | 80 | for ((i=$depth;i<=${#char};)) { 81 | while [[ -n $char ]] || [[ -n $includes ]];do 82 | printChar=$(printf "%c\n" "$char") 83 | printIncludes=$(printf "%c\n" "$includes" ) 84 | 85 | [[ -z $printIncludes ]] && { 86 | printf "%s\n" "true" 87 | return $true 88 | 89 | } # did this to fix a bug, if the string can be cut to the ending and printInlcudes become null that means all other test was true 90 | 91 | 92 | 93 | if [[ $printChar != $printIncludes ]];then 94 | printf "%s\n" "false" && return $false 95 | fi 96 | char=${char#*?} 97 | includes=${includes#*?} 98 | : $(( i++ )) 99 | done 100 | } 101 | } 102 | 103 | endsWith() { 104 | local char="${1}" 105 | local endswith="${2}" 106 | declare -i depth="${3}" 107 | 108 | { 109 | [[ -z "$char" ]] || [[ -z "$endswith" ]] 110 | } && printf "%s\n" "Usage:${FUNCNAME} string endToCheck ?depth" && return $false 111 | 112 | (( depth == 0 )) && depth=${#char} 113 | 114 | 115 | ( 116 | character="${char}" 117 | for ((i=1;i<=$depth;i++)) { 118 | while [ -n "$character" ];do 119 | 120 | printOne=$(printf "%c" "$character") 121 | character=${character#*"${printOne}"} 122 | 123 | (( i == depth )) && { 124 | 125 | [[ "${printOne}" == "${endswith}" ]] && { 126 | printf "%s\n" "true" && return $true\ 127 | 128 | } || { 129 | printf "%s\n" "false" 130 | return $false 131 | } 132 | 133 | 134 | } || { 135 | 136 | continue 2; 137 | } 138 | 139 | done 140 | 141 | } 142 | ) 143 | } 144 | offset() { 145 | # Bug: It does not deal with negative numbers 146 | # better still use ${var:position:length} to get the offset of a value 147 | local string=${1} 148 | local position=${2} 149 | local length=${3} 150 | 151 | [[ -z "${string}" ]] && printf "%s\n" "Error: String to work with was not specified" && \ 152 | printf "%s\n" "Usage:${FUNCNAME} string ?postion ?length" && return $false 153 | if [[ -z "${position}" ]] && [[ -z "${length}" ]];then 154 | printf "%s\n" "${string}" 155 | return $true 156 | fi 157 | 158 | [[ "${position}" =~ [A-Za-z] ]] && \ 159 | printf "%s\n" "Error: Required an integer for postion but got a string" && return $false 160 | [[ "${length}" =~ [A-Za-z] ]] && \ 161 | printf "%s\n" "Error: Required an integer for length but got a string" && return $false 162 | if [[ ${position} -gt ${#string} ]] || [[ ${length} -gt ${#string} ]] ;then 163 | printf "%s\n" "Error: index is greater than string length" 164 | return $false 165 | fi 166 | 167 | ( 168 | # Kill all the variables declared inside this subshell when done 169 | # Using index++ inside the for (()) introduced an unwanted feature 170 | # i had to take it to the body of the while loop 171 | for ((index=0;index<=${#string};)) { 172 | 173 | while [ -n "${string}" ];do 174 | 175 | (( index == position )) && { 176 | # If the value of index equals to the position specified run this block of code 177 | # if length is null print the string and return from this function ${FUNCNAME} 178 | [[ -z "${length}" ]] && printf "%s\n" "${string}" && return $true 179 | 180 | # if length is not null get the offset specified by the user 181 | for ((ind=0;ind<=${#string};)) { 182 | 183 | while [ -n "${string}" ];do 184 | 185 | (( ${#string} == length )) && { 186 | echo "$string" && return $true; 187 | } 188 | string=${string%$(printf "%c" "$(rev <<<${string})")*} 189 | # : >> don't run the result of $(( ind++ )) 190 | # better still ind=$(( ind++ )) 191 | : $(( ind++ )) 192 | done 193 | } 194 | } 195 | 196 | printOneChar=$(printf "%c" "${string}" ) 197 | string=${string#*$printOneChar} 198 | : $((index++)) 199 | done 200 | } 201 | ) 202 | } 203 | 204 | isInteger() { 205 | local number="${1}" 206 | 207 | [[ -z "${number}" ]] && { 208 | printf "%s\n" "Usage: ${FUNCNAME} number" 209 | return $false 210 | } 211 | 212 | # check if the content of $number is an alphabet or any punctuation mark 213 | 214 | ( 215 | for ((i=0;i<=${#number};)) { 216 | while [ -n "$number" ];do 217 | printNumber=$(printf "%c" "$number") 218 | [[ ! $printNumber == [0-9] ]] && return $false 219 | number=${number#*?} 220 | : $(( i++ )) 221 | done 222 | } 223 | ) 224 | 225 | [[ $? == 1 ]] && return $false 226 | 227 | #if egrep -q "([[:alpha:]])|([[:punct:]])" <<<"${number}";then 228 | #return $false 229 | #fi 230 | 231 | return $true 232 | } 233 | 234 | int() { 235 | # get all the integers before the decimal point 236 | # non integers values will cause an error 237 | local integer="${1}" 238 | 239 | [[ -z "${integer}" ]] && { 240 | printf "%s\n" "Usage: ${FUNCNAME} number" 241 | return $false 242 | } 243 | 244 | isInteger $integer 245 | 246 | # if the exit status of "isInteger $integer" greater than 0 enter the below block of code 247 | [[ $? != 0 ]] && { 248 | # setting integer to another variable 249 | local privInteger=$integer 250 | local ind; 251 | for ((ind=0;ind<=${#privInteger};)) { 252 | 253 | # while privInteger is non-zero i.e if there is still text in privInteger 254 | 255 | while [ -n "$privInteger" ];do 256 | # save the first character of privInteger in printchar variable 257 | local printchar=$(printf "%c" "${privInteger}" ) 258 | # cut the first character in privInteger until there is nothing in privInteger 259 | privInteger=${privInteger#*$printchar} 260 | # incase printchar variable does not contain 0-9 or . 261 | [[ ! $printchar =~ ([0-9\.]) ]] && { 262 | # declare a variable space 263 | local space="" 264 | # save integer again on another variable 265 | local int=$integer 266 | local err; 267 | for ((err=0;err<=${#int};)) { 268 | # this block of code , will add a single space to the space variable 269 | # aslong as int is non-zero and $pchar(see the next while loop ) does not equal printchar 270 | # Note:- $printchar is the single value that does not equal 0-9 or . 271 | # if a match is find return from this function with return code of 1 272 | while [ -n "${int}" ];do 273 | local pchar=$(printf "%c" "${int}") 274 | [[ $pchar == $printchar ]] && { 275 | printf "%s\n" "${integer}" 276 | printf "%s\n" "$space^Invalid character" 277 | return $false 278 | } 279 | space+=" " 280 | : $(( err++ )) 281 | # cut a single value from int until there is nothing inside 282 | int=${int#*$pchar} 283 | done 284 | 285 | } ; #end of $err 286 | 287 | 288 | } ; # End of $printchar 289 | 290 | #for ((period=0;period<=${#integer};period++)) { 291 | # echo $printchar 292 | # } 293 | 294 | : $(( ind++ )) 295 | done 296 | # printchar does not equal any punct value 297 | # cut any leading . forward 298 | printf "%s\n" "${integer%%.*}" 299 | return $true 300 | } 301 | } 302 | printf "%s\n" "${integer}" 303 | return $true 304 | } 305 | raw() { 306 | # you might not need this 307 | local str="${1}" 308 | [[ -z "${@}" ]] && { 309 | printf "%s\n" "Usage: raw string" 310 | } 311 | sed 's|\\|\\\\|g' <<<"${str}" 312 | } 313 | destructure() { 314 | # do not quote the array argument ( first agument ) 315 | # it is important you quote the second argument to this function 316 | # associative arrays work in alphabetical order 317 | # use "," to separate the variables to assign each array element to 318 | # for example 319 | # array=( bash ksh zsh ) 320 | # destructure ${array[@]} "var1,var2,var3" 321 | # echo $var1 322 | # echo $var2 323 | # echo $var3 324 | [[ -z "${@}" ]] && { 325 | 326 | printf "%s\n" "Usage:${FUNCNAME} array values" 327 | printf "%s\n" "destructure \${array[@]} \"var1,var2,,var3\"" 328 | printf "%s\n" "The array should not be quoted but the variables to assign the array element should be quoted" 329 | return $false 330 | } 331 | 332 | # Substract 1 from the total number of arguments 333 | local arrayLength=$(( ${#@} - 1)) 334 | # get the location of the last argument 335 | local str=$(( arrayLength + 1 )) 336 | # get the value of the last argument using indirect reference ( ! ) 337 | local strToDestruct="${!str}," 338 | declare -i y=0; 339 | local varList; 340 | # loop through the length of arrayLength 341 | for ((i=0;i<=$arrayLength;)) { 342 | # for j in the total number of arguments 343 | for j ; do 344 | # if the value of i equals the length of our arrayLength variable, break from the 2 loops 345 | (( i == arrayLength )) && break 2; 346 | while [ -n "$strToDestruct" ] ;do 347 | (( y == arrayLength )) && break 3; 348 | local destruct=${strToDestruct%%,*} 349 | strToDestruct=${strToDestruct#*,} 350 | { 351 | [[ -z "${destruct}" ]] || [[ "${destruct}" == +( ) ]] 352 | } && { 353 | declare -x null="null" 354 | varList+=${!destruct}, # ${null} >> ignore this comment 355 | : $(( y++ )) 356 | continue 2 357 | } 358 | declare -g $destruct=$j 359 | varList+=${!destruct}, 360 | : $(( y++ )) 361 | continue 2; 362 | 363 | done 364 | : $(( i++ )) 365 | done 366 | } 367 | varList=${varList%,*} 368 | } 369 | 370 | ...() { 371 | # Spread a bunch of string inside an array 372 | # for example:- 373 | # str=bash 374 | # array=( $(... $str) ) 375 | # echo ${str[@]} 376 | # b a s h 377 | 378 | local stringToSpread="$@" 379 | 380 | [[ -z "${stringToSpread}" ]] && { 381 | 382 | printf "%s\n" "Usage: ${FUNCNAME} string" 383 | return $false 384 | } 385 | 386 | [[ ${#@} -eq 1 ]] && { 387 | for ((i=0;i<=${#stringToSpread};i++)) { 388 | while [[ -n "${stringToSpread}" ]];do 389 | printf "%c\n" "${stringToSpread}" 390 | stringToSpread=${stringToSpread#*?} 391 | done 392 | } 393 | } 394 | } 395 | 396 | foreach() { 397 | # dont'quote the array arugment ( i.e the first agument ) 398 | # If you pass in a function as the callback using the function command you should wrap it in single quotes 399 | local array=$(( ${#@} - 1 )) 400 | local callback=$(( array + 1 )) 401 | declare -ga newArray 402 | [[ -z ${#@} ]] && { 403 | printf "%s\n" "Usage: ${FUNCNAME} array callback" 404 | return $false 405 | } 406 | # stupid hack to test if argument 1 is an array 407 | [[ ${array} -le 1 ]] && { 408 | printf "%s\n" "Error: first argument is not an Array" 409 | return $false 410 | } 411 | 412 | [[ -z "${callback}" ]] && { 413 | printf "%s\n" "Error: No Callback argument was provided" 414 | return $false 415 | } 416 | declare -F ${!callback} >/dev/null 417 | 418 | [[ $? -ge 1 ]] && { 419 | #Evaluate the callback 420 | eval ${!callback} &>/dev/null 421 | #If the previous command exit status is greater or equal to 1 422 | [[ $? -ge 1 ]] && { 423 | printf "%s\n" "Error: bad array callback" 424 | return $false 425 | } 426 | 427 | local command=$(egrep -o "\w+\(\)" <<<${!callback}) 428 | command=${command/()/} 429 | for ((i=0;i<=${#array};)) { 430 | for j; do 431 | (( i == array )) && break 2; 432 | newArray+=( $( $command $j ) ) 433 | : $(( i++ )) 434 | done 435 | } 436 | echo "${newArray[@]}" 437 | return $true 438 | } 439 | 440 | for ((i=0;i<=${#array};)) { 441 | for j;do 442 | (( i == array )) && break 2; 443 | newArray+=( $( ${!callback} $j) ) 444 | 445 | : $(( i++ )) 446 | done 447 | } 448 | echo "${newArray[@]}" 449 | } 450 | 451 | copyWithin() { 452 | local array=$1 453 | declare -i indexToCopyFrom=$2 454 | declare -i indexToCopyTo=$3 455 | read -a array <<<"$array" 456 | local valueOfIndexToCopyFrom=${array[$indexToCopyFrom]} 457 | local valueOfIndexToCopyTo=${array[$indexToCopyTo]} 458 | { 459 | [[ -z ${@} ]] || [[ -z "$array" ]] 460 | } && { 461 | printf "%s\n" "Usage: copyWithin arrayArgument indexToCopyFrom indexToCopyto" 462 | return $false 463 | } 464 | array[$indexToCopyTo]=$valueOfIndexToCopyFrom 465 | echo ${array[@]} 466 | return $true; 467 | } 468 | <<'EOF' 469 | keys() { 470 | local array=$1 471 | read -a array <<<"$array" 472 | local getInfo=$(declare -p array) 473 | [[ -z "$array" ]] && { 474 | printf "%s\n" "Usage: keys arrayArgument" 475 | return $false 476 | } 477 | a=( ["theif"]="victory" ["theif1"]="favour" ["theif2"]="johnson" ) 478 | local getInfo=$(declare -p a) 479 | arrKeys=$(egrep -o '(\[[[:alnum:]]+\])' <<<"$getInfo") 480 | echo \'${arrKeys}\' 481 | } 482 | 483 | declare -A a=( ["theif"]="victory" ["theif1"]="favour" ["theif2"]="johnson" ) 484 | 485 | keys "${a[*]}" 486 | EOF 487 | --------------------------------------------------------------------------------