3 # This defines some general, useful functions.
5 #hmmm: starting to get a bit beefy in here. perhaps there is a good way to refactor the functions into more specific folders, if they aren't really totally general purpose?
9 # test whether we've been here before or not.
11 type function_sentinel &>/dev/null
13 # there was no error, so we can skip the inits.
14 if [ ! -z "$DEBUG_FEISTY_MEOW" ]; then
15 echo "skipping function definitions, because already defined."
22 if [ -z "$skip_all" ]; then
24 if [ ! -z "$DEBUG_FEISTY_MEOW" ]; then
25 echo "feisty meow function definitions beginning now..."
28 # a handy little method that can be used for date strings. it was getting
29 # really tiresome how many different ways the script did the date formatting.
30 function date_stringer() {
32 if [ -z "$sep" ]; then sep='_'; fi
33 date +"%Y$sep%m$sep%d$sep%H%M$sep%S" | tr -d '/\n/'
36 # makes a directory of the name specified and then tries to change the
37 # current directory to that directory.
39 if [ ! -d "$1" ]; then mkdir -p "$1"; fi
43 # returns true if the variable is an array.
45 [[ "$(declare -p $1)" =~ "declare -a" ]]
48 # returns true if the name provided is a defined alias.
54 # makes the status of pipe number N (passed as first parameter) into the
55 # main return value (i.e., the value for $?). this is super handy to avoid
56 # repeating the awkward looking code below in multiple places.
57 function promote_pipe_return()
59 ( exit ${PIPESTATUS[$1]} )
64 function fm_username()
66 # see if we can get the user name from the login name. oddly this sometimes doesn't work.
67 local custom_user="$(logname 2>/dev/null)"
68 if [ -z "$custom_user" ]; then
69 # try the normal unix user variable.
72 if [ -z "$custom_user" ]; then
73 # try the windows user variable.
74 custom_user="$USERNAME"
81 # displays the value of a variable in bash friendly format.
86 local varname="$1"; shift
87 if [ -z "$varname" ]; then
91 if is_alias "$varname"; then
92 #echo found $varname is alias
93 local tmpfile="$(mktemp $TMP/aliasout.XXXXXX)"
94 alias $varname | sed -e 's/.*=//' >$tmpfile
95 echo "alias $varname=$(cat $tmpfile)"
97 elif [ -z "${!varname}" ]; then
98 echo "$varname undefined"
100 if is_array "$varname"; then
101 #echo found $varname is array var
103 eval temparray="(\${$varname[@]})"
104 echo "$varname=(${temparray[@]})"
105 #hmmm: would be nice to print above with elements enclosed in quotes, so that we can properly
106 # see ones that have spaces in them.
108 #echo found $varname is simple
109 echo "$varname=${!varname}"
118 # when passed a list of things, this will return the unique items from that list as an echo.
121 # do the uniquification: split the space separated items into separate lines, then
122 # sort the list, then run the uniq tool on the list. results will be packed back onto
123 # one line when invoked like: local fredlist="$(uniquify a b c e d a e f a e d b)"
124 echo $* | tr ' ' '\n' | sort | uniq
127 # sets the variable in parameter 1 to the value in parameter 2, but only if
128 # that variable was undefined.
129 function set_var_if_undefined()
131 local var_name="$1"; shift
132 local var_value="$1"; shift
133 if [ -z "${!var_name}" ]; then
134 eval export $var_name="$var_value"
140 function success_sound()
142 if [ ! -z "$CLAM_FINISH_SOUND" ]; then
143 bash $FEISTY_MEOW_SCRIPTS/multimedia/sound_play.sh "$CLAM_FINISH_SOUND"
147 function error_sound()
149 if [ ! -z "$CLAM_ERROR_SOUND" ]; then
150 bash $FEISTY_MEOW_SCRIPTS/multimedia/sound_play.sh "$CLAM_ERROR_SOUND"
156 # echoes the maximum number of columns that the terminal supports. usually
157 # anything you print to the terminal with length less than (but not equal to)
158 # maxcols will never wrap.
159 function get_maxcols()
161 # calculate the number of columsn in the terminal.
162 local cols=$(stty size | awk '{print $2}')
168 # checks the result of the last command that was run, and if that failed,
169 # then this complains and exits from bash. the function parameters are
170 # used as the message to print as a complaint.
171 function exit_on_error()
173 if [ $? -ne 0 ]; then
174 echo -e "\n\nan important action failed and this script will stop:\n\n$*\n\n*** Exiting script..."
180 # like exit_on_error, but will keep going after complaining.
181 function continue_on_error()
183 if [ $? -ne 0 ]; then
184 echo -e "\n\na problem occurred, but we can continue:\n\n$*\n\n=> Continuing script..."
191 # accepts any number of arguments and outputs them to the feisty meow event log.
192 function log_feisty_meow_event()
194 echo -e "$(date_stringer) -- ${USER}@$(hostname): $*" >> "$FEISTY_MEOW_EVENT_LOG"
199 # wraps secure shell with some parameters we like, most importantly to enable X forwarding.
203 # we remember the old terminal title, then force the TERM variable to a more generic
204 # version for the other side (just 'linux'); we don't want the remote side still
205 # thinking it's running xterm.
208 #hmmm: why were we doing this? it scorches the user's logged in session, leaving it without proper terminal handling.
209 # # we save the value of TERM; we don't want to leave the user's terminal
210 # # brain dead once we come back from this function.
211 # local oldterm="$TERM"
214 /usr/bin/ssh -Y -C "${args[@]}"
216 # # restore the terminal variable also.
219 restore_terminal_title
220 if [ ! -z "$DEBUG_FEISTY_MEOW" ]; then
221 echo TERM title restored to prior value
227 # locates a process given a search pattern to match in the process list.
228 # supports a single command line flag style parameter of "-u USERNAME";
229 # if the -u flag is found, a username is expected afterwards, and only the
230 # processes of that user are considered.
232 local -a patterns=("${@}")
234 #echo patterns list is: "${patterns[@]}"
238 if [ "${patterns[0]}" == "-u" ]; then
239 user_flag="-u ${patterns[1]}"
240 #echo "found a -u parm and user=${patterns[1]}"
241 # void the two elements with that user flag so we don't use them as patterns.
242 unset patterns[0] patterns[1]=
248 local PID_DUMP="$(mktemp "$TMP/zz_pidlist.XXXXXX")"
251 if [ "$OS" == "Windows_NT" ]; then
252 # gets cygwin's (god awful) ps to show windoze processes also.
253 local EXTRA_DOZER_FLAGS="-W"
254 # pattern to use for peeling off the process numbers.
255 local pid_finder_pattern='s/ *\([0-9][0-9]*\) *.*$/\1/p'
258 # flags which clean up the process listing output on unixes.
259 # apparently cygwin doesn't count as a type of unix, because their
260 # crummy specialized ps command doesn't support normal ps flags.
261 local EXTRA_UNIX_FLAGS="-o pid,args"
262 # pattern to use for peeling off the process numbers.
263 local pid_finder_pattern='s/^[[:space:]]*\([0-9][0-9]*\).*$/\1/p'
266 /bin/ps $EXTRA_DOZER_FLAGS $EXTRA_UNIX_FLAGS $user_flag | tail -n +2 >$PID_DUMP
268 #echo got all this stuff in the pid dump file:
272 # search for the pattern the user wants to find, and just pluck the process
273 # ids out of the results.
275 for i in "${patterns[@]}"; do
276 PIDS_SOUGHT+=($(cat $PID_DUMP \
278 | sed -n -e "$pid_finder_pattern"))
281 #echo pids sought list became:
282 #echo "${PIDS_SOUGHT[@]}"
285 if [ ${#PIDS_SOUGHT[*]} -ne 0 ]; then
286 local PIDS_SOUGHT2=$(printf -- '%s\n' ${PIDS_SOUGHT[@]} | sort | uniq)
288 PIDS_SOUGHT=${PIDS_SOUGHT2[*]}
289 echo ${PIDS_SOUGHT[*]}
294 # finds all processes matching the pattern specified and shows their full
295 # process listing (whereas psfind just lists process ids).
298 echo "psa finds processes by pattern, but there was no pattern on the command line."
301 local -a patterns=("${@}")
302 p=$(psfind "${patterns[@]}")
308 if [ "${patterns[0]}" == "-u" ]; then
309 # void the two elements with that user flag so we don't use them as patterns.
310 unset patterns[0] patterns[1]=
314 echo "Processes matching ${patterns[@]}..."
316 if [ -n "$IS_DARWIN" ]; then
319 # only print the header the first time.
320 if [ -z "$fuzil_sentinel" ]; then
323 ps $i -w -u | sed -e '1d'
328 # cases besides mac os x's darwin.
329 if [ "$OS" == "Windows_NT" ]; then
330 # special case for windows.
333 ps -W -p $curr | tail -n +2
336 # normal OSes can handle a nice simple query.
344 #hmmm: holy crowbars, this is an old one. do we ever still have any need of it?
345 # an unfortunately similarly named function to the above 'ps' as in process
346 # methods, but this 'ps' stands for postscript. this takes a postscript file
347 # and converts it into pcl3 printer language and then ships it to the printer.
348 # this mostly makes sense for an environment where one's default printer is
349 # pcl. if the input postscript causes ghostscript to bomb out, there has been
350 # some good success running ps2ps on the input file and using the cleaned
351 # postscript file for printing.
352 function ps2pcl2lpr() {
354 gs -sDEVICE=pcl3 -sOutputFile=- -sPAPERSIZE=letter "$i" | lpr -l
358 #hmmm: not really doing anything yet; ubuntu seems to have changed from pulseaudio in 17.04?
359 # restarts the sound driver.
360 function fix_sound_driver() {
361 # stop bash complaining about blank function body.
364 # sudo service alsasound restart
365 #elif pulse something
376 #hmmm: ugly absolute path here.
378 restore_terminal_title
381 # switches from a /X/path form to an X:/ form. this also processes cygwin paths.
382 function unix_to_dos_path() {
383 # we usually remove dos slashes in favor of forward slashes.
385 if [[ ! "$OS" =~ ^[Ww][iI][nN] ]]; then
386 # fake this value for non-windows (non-cygwin) platforms.
389 # for cygwin, we must replace the /home/X path with an absolute one, since cygwin
390 # insists on the /home form instead of /c/cygwin/home being possible. this is
391 # super frustrating and nightmarish.
392 DOSSYHOME="$(cygpath -am "$HOME")"
395 if [ ! -z "$SERIOUS_SLASH_TREATMENT" ]; then
396 # unless this flag is set, in which case we force dos slashes.
397 echo "$1" | sed -e "s?^$HOME?$DOSSYHOME?g" | sed -e 's/\\/\//g' | sed -e 's/\/cygdrive//' | sed -e 's/\/\([a-zA-Z]\)\/\(.*\)/\1:\/\2/' | sed -e 's/\//\\/g'
399 echo "$1" | sed -e "s?^$HOME?$DOSSYHOME?g" | sed -e 's/\\/\//g' | sed -e 's/\/cygdrive//' | sed -e 's/\/\([a-zA-Z]\)\/\(.*\)/\1:\/\2/'
403 # # switches from an X:/ form to a /cygdrive/X/path form. this is only useful
404 # # for the cygwin environment currently.
405 # function dos_to_unix_path() {
406 # # we always remove dos slashes in favor of forward slashes.
407 ##old: echo "$1" | sed -e 's/\\/\//g' | sed -e 's/\([a-zA-Z]\):\/\(.*\)/\/\1\/\2/'
408 # echo "$1" | sed -e 's/\\/\//g' | sed -e 's/\([a-zA-Z]\):\/\(.*\)/\/cygdrive\/\1\/\2/'
411 # returns a successful value (0) if this system is debian or ubuntu.
412 function debian_like() {
413 # decide if we think this is debian or ubuntu or a variant.
414 DEBIAN_LIKE=$(if [ ! -z "$(grep -i debian /etc/issue)" \
415 -o ! -z "$(grep -i ubuntu /etc/issue)" ]; then echo 1; else echo 0; fi)
416 if [ $DEBIAN_LIKE -eq 1 ]; then
417 # success; this is debianish.
420 # this seems like some other OS.
425 #bork # su function: makes su perform a login.
426 #bork # for some OSes, this transfers the X authority information to the new login.
427 #bork function su() {
428 #bork if debian_like; then
429 #bork # debian currently requires the full version which imports X authority
430 #bork # information for su.
432 #bork # get the x authority info for our current user.
433 #bork source "$FEISTY_MEOW_SCRIPTS/security/get_x_auth.sh"
435 #bork if [ -z "$X_auth_info" ]; then
436 #bork # if there's no authentication info to pass along, we just do a normal su.
439 #bork # under X, we update the new login's authority info with the previous
441 #bork (unset XAUTHORITY; /bin/su -l $* -c "$X_auth_info ; export DISPLAY=$DISPLAY ; bash")
444 #bork # non-debian supposedly doesn't need the extra overhead any more.
445 #bork # or at least suse doesn't, which is the other one we've tested on.
450 # this function wraps the normal sudo by ensuring we replace the terminal
451 # label before we launch what they're passing to sudo. we also ensure that
452 # the feisty meow environment is recreated; normal subshells don't need
453 # this, but when switching identity with sudo, it seems important. yet,
454 # we also don't want to hose up their normal sudo actions, such as passing
455 # along the current environment, should the user choose.
458 # hoist our X authorization info in case environment is passed along;
459 # this can allow root to use our display to show Xorg windows.
460 if [ ! -z "$DISPLAY" ]; then
461 export IMPORTED_XAUTH="$(xauth list $DISPLAY | head -n 1 | awk '{print $3}')"
463 # prep a simple command string here, rather than messing with arguments
464 # in the already complicated command below. i was seeing some really
465 # screwy behavior trying to expand $@ when embedded for the bash -c flag,
466 # but making the variable ahead of time gets rid of that.
467 cmd="/usr/bin/sudo ""$@"
469 # omit any variables that are either wrong for a different user or used
470 # to shield the feisty meow scripts from reconfiguring. when we do the
471 # sudo, we want a fresh start for feisty meow at least.
472 # our approach to launching sudo is further complicated by our sentinel
473 # alias, which normally is passed to any subshells (to prevent recreating
474 # aliases). we turn off the expand_aliases shell option to avoid passing
475 # the sentinel, which ensures aliases do get recreated for the new user.
477 CORE_VARIABLES_LOADED= \
478 FEISTY_MEOW_SCRIPTS_LOADED= \
481 bash +O expand_aliases -c "$cmd"
483 restore_terminal_title
487 # trashes the .#blah files that cvs and subversion leave behind when finding conflicts.
488 # this kind of assumes you've already checked them for any salient facts.
489 function clean_cvs_junk() {
491 find $i -follow -type f -iname ".#*" -exec perl $FEISTY_MEOW_SCRIPTS/files/safedel.pl {} ";"
495 # overlay for nechung binary so that we can complain less grossly about it when it's missing.
497 local wheres_nechung=$(which nechung 2>/dev/null)
498 if [ -z "$wheres_nechung" ]; then
499 echo "The nechung oracle program cannot be found. You may want to consider"
500 echo "rebuilding the feisty meow applications with this command:"
501 echo "bash $FEISTY_MEOW_SCRIPTS/generator/produce_feisty_meow.sh"
508 # recreates all the generated files that the feisty meow scripts use.
509 function regenerate() {
510 # do the bootstrapping process again.
512 echo "regenerating feisty meow script environment."
513 bash $FEISTY_MEOW_SCRIPTS/core/reconfigure_feisty_meow.sh
515 # force a full reload by turning off sentinel variables and methods.
516 unset -v CORE_VARIABLES_LOADED FEISTY_MEOW_LOADING_DOCK USER_CUSTOMIZATIONS_LOADED
517 unalias CORE_ALIASES_LOADED &>/dev/null
518 unset -f function_sentinel
519 # reload feisty meow environment in current shell.
520 log_feisty_meow_event "reloading the feisty meow scripts for $USER in current shell."
521 source "$FEISTY_MEOW_SCRIPTS/core/launch_feisty_meow.sh"
522 # run nechung oracle to give user a new fortune.
524 restore_terminal_title
527 # merges a set of custom scripts into the feisty meow environment. can be
528 # passed a name to use as the custom scripts source folder (found on path
529 # $FEISTY_MEOW_SCRIPTS/customize/{name}), or it will try to guess the name
530 # by using the login name.
531 function recustomize()
533 local custom_user="$1"; shift
534 if [ -z "$custom_user" ]; then
535 # default to login name if there was no name provided.
536 custom_user="$(fm_username)"
537 # we do intend to use the login name here to get the login name and to ignore
538 # if the user has sudo root access; we don't want to provide a custom
541 # chop off any email address style formatting to leave just the name.
542 custom_user="$(echo "$custom_user" | cut -f1 -d'@')"
546 if [ ! -d "$FEISTY_MEOW_SCRIPTS/customize/$custom_user" ]; then
547 echo -e "the customization folder for '$custom_user' is missing:
549 $FEISTY_MEOW_SCRIPTS/customize/$custom_user
551 we will skip recustomization, but these other customizations are available:
553 # a little tr and sed magic to fix the carriage returns into commas.
554 local line="$(find $FEISTY_MEOW_SCRIPTS/customize -mindepth 1 -maxdepth 1 -type d -exec basename {} ';' | tr '\n' '&' | sed 's/&/, /g' | sed -e 's/, $//')"
555 # make the line feeds and carriage returns manageable with tr.
556 # convert the ampersand, our weird replacement for EOL, with a comma + space in sed.
557 # last touch with sed removes the last comma.
562 # recreate the feisty meow loading dock.
563 regenerate >/dev/null
565 # jump into the loading dock and make our custom link.
566 pushd "$FEISTY_MEOW_LOADING_DOCK" &>/dev/null
567 if [ -h custom ]; then
568 # there's an existing link, so remove it.
571 # make sure we cleaned up the area before we re-link.
572 if [ -h custom -o -d custom -o -f custom ]; then
574 Due to an over-abundance of caution, we are not going to remove an unexpected
575 'custom' object found in the file system. This object is located in the
576 feisty meow loading dock here: $(pwd)
577 And here is a description of the rogue 'custom' object:
581 If you are pretty sure that this is just a remnant of an older approach in
582 feisty meow, where we copied the custom directory rather than linking it
583 (and it most likely is just such a bit of cruft of that nature), then please
584 remove that old remnant 'custom' item, for example by saying:
585 /bin/rm -rf \"custom\" ; popd
586 Sorry for the interruption, but we want to make sure this removal wasn't
587 automatic if there is even a small amount of doubt about the issue."
591 # create the custom folder as a link to the customizations.
592 ln -s "$FEISTY_MEOW_SCRIPTS/customize/$custom_user" custom
596 # now take into account all the customizations by regenerating the feisty meow environment.
599 restore_terminal_title
602 # generates a random password where the first parameter is the number of characters
603 # in the password (default 20) and the second parameter specifies whether to use
604 # special characters (1) or not (0).
605 # found function at http://legroom.net/2010/05/06/bash-random-password-generator
606 function random_password()
608 [ "$2" == "0" ] && CHAR="[:alnum:]" || CHAR="[:graph:]"
609 cat /dev/urandom | tr -cd "$CHAR" | head -c ${1:-32}
613 # a wrapper for the which command that finds items on the path. some OSes
614 # do not provide which, so we want to not be spewing errors when that
619 which which &>/dev/null
620 if [ $? -ne 0 ]; then
621 # there is no which command here. we produce nothing due to this.
624 echo $(which $to_find)
627 function add_cygwin_drive_mounts() {
628 for i in c d e f g h q z ; do
629 #hmmm: improve this by not adding the link if already there, or if the drive is not valid.
630 ln -s /cygdrive/$i $i
634 ############################
636 # takes a file to modify, and then it will replace any occurrences of the
637 # pattern provided as the second parameter with the text in the third
639 function replace_pattern_in_file()
641 local file="$1"; shift
642 local pattern="$1"; shift
643 local replacement="$1"; shift
644 if [ -z "$file" -o -z "$pattern" -o -z "$replacement" ]; then
645 echo "replace_pattern_in_file: needs a filename, a pattern to replace, and the"
646 echo "text to replace that pattern with."
649 sed -i -e "s%$pattern%$replacement%g" "$file"
652 # similar to replace_pattern_in_file, but also will add the new value
653 # when the old one did not already exist in the file.
654 function replace_if_exists_or_add()
656 local file="$1"; shift
657 local phrase="$1"; shift
658 local replacement="$1"; shift
659 if [ -z "$file" -o ! -f "$file" -o -z "$phrase" -o -z "$replacement" ]; then
660 echo "replace_if_exists_or_add: needs a filename, a phrase to replace, and the"
661 echo "text to replace that phrase with."
664 grep "$phrase" "$file" >/dev/null
665 # replace if the phrase is there, otherwise add it.
666 if [ $? -eq 0 ]; then
667 replace_pattern_in_file "$file" "$phrase" "$replacement"
669 # this had better be the complete line.
670 echo "$replacement" >>"$file"
674 ############################
676 # finds a variable (first parameter) in a particular property file
677 # (second parameter). the expected format for the file is:
679 function seek_variable()
681 local find_var="$1"; shift
682 local file="$1"; shift
683 if [ -z "$find_var" -o -z "$file" -o ! -f "$file" ]; then
684 echo -e "seek_variable: needs two parameters, firstly a variable name, and\nsecondly a file where the variable's value will be sought." 1>&2
689 if [ ${#line} -eq 0 ]; then continue; fi
690 # split the line into the variable name and value.
691 IFS='=' read -a assignment <<< "$line"
692 local var="${assignment[0]}"
693 local value="${assignment[1]}"
694 if [ "${value:0:1}" == '"' ]; then
695 # assume the entry was in quotes and remove them.
696 value="${value:1:$((${#value} - 2))}"
698 if [ "$find_var" == "$var" ]; then
704 # finds a variable (first parameter) in a particular XML format file
705 # (second parameter). the expected format for the file is:
706 # ... name="varX" value="valueX" ...
707 function seek_variable_in_xml()
709 local find_var="$1"; shift
710 local file="$1"; shift
711 if [ -z "$find_var" -o -z "$file" -o ! -f "$file" ]; then
712 echo "seek_variable_in_xml: needs two parameters, firstly a variable name, and"
713 echo "secondly an XML file where the variable's value will be sought."
718 if [ ${#line} -eq 0 ]; then continue; fi
719 # process the line to make it more conventional looking.
720 line="$(echo "$line" | sed -e 's/.*name="\([^"]*\)" value="\([^"]*\)"/\1=\2/')"
721 # split the line into the variable name and value.
722 IFS='=' read -a assignment <<< "$line"
723 local var="${assignment[0]}"
724 local value="${assignment[1]}"
725 if [ "${value:0:1}" == '"' ]; then
726 # assume the entry was in quotes and remove them.
727 value="${value:1:$((${#value} - 2))}"
729 if [ "$find_var" == "$var" ]; then
735 ############################
737 # goes to a particular directory passed as parameter 1, and then removes all
738 # the parameters after that from that directory.
739 function push_whack_pop()
741 local dir="$1"; shift
742 pushd "$dir" &>/dev/null
743 if [ $? -ne 0 ]; then echo failed to enter dir--quitting.; fi
744 rm -rf $* &>/dev/null
745 if [ $? -ne 0 ]; then echo received a failure code when removing.; fi
751 # new breed of definer functions goes here. still in progress.
753 # defines an alias and remembers that this is a new or modified definition.
754 # if the feisty meow codebase is unloaded, then so are all the aliases that
756 function define_yeti_alias()
758 # if alias exists already, save old value for restore,
759 # otherwise save null value for restore,
760 # have to handle unaliasing if there was no prior value of one
762 # add alias name to a list of feisty defined aliases.
764 #hmmm: first implem, just do the alias and get that working...
773 #hmmm: this points to an extended functions file being needed; not all of these are core.
775 # displays documentation in "md" formatted files.
778 local file="$1"; shift
779 pandoc "$file" | lynx -stdin
784 # just shows a separator line for an 80 column console, or uses the first
785 # parameter as the number of columns to expect.
789 if [ -z "$count" ]; then
794 for ((i=0; i < $count - 1; i++)); do
800 # alias for separator.
808 # count the number of sub-directories in a directory and echo the result.
809 function count_directories()
811 local subbydir="$1"; shift
812 numdirs="$(find "$subbydir" -mindepth 1 -maxdepth 1 -type d | wc -l)"
816 # takes a string and capitalizes just the first character. any capital letters in the remainder of
817 # the string are made lower case. the processed string is returned by an echo.
818 function capitalize_first_char()
820 local to_dromedary="$1"; shift
821 to_dromedary="$(tr '[:lower:]' '[:upper:]' <<< ${to_dromedary:0:1})$(tr '[:upper:]' '[:lower:]' <<< ${to_dromedary:1})"
825 # given a source path and a target path, this will make a symbolic link from
826 # the source to the destination, but only if the source actually exists.
827 function make_safe_link()
829 local src="$1"; shift
830 local target="$1"; shift
832 if [ -d "$src" ]; then
833 ln -s "$src" "$target"
834 exit_on_error "Creating symlink from '$src' to '$target'"
836 echo "Created symlink from '$src' to '$target'."
839 # pretty prints the json files provided as parameters.
840 function clean_json()
842 if [ -z "$*" ]; then return; fi
845 local file="$1"; shift
846 if [ -z "$file" ]; then break; fi
847 if [ ! -f "$file" ]; then "echo File '$file' does not exist."; continue; fi
848 temp_out="$TMP/$file.view"
849 cat "$file" | python -m json.tool > "$temp_out"
850 show_list+=($temp_out)
851 continue_on_error "pretty printing '$file'"
853 filedump "${show_list[@]}"
859 # only print our special headers or text fields.
863 grep -i "\"text\":\|^=.*" |
864 sed -e "s/\\\\r/$CR/g" -e "s/\\\\n/\\$LF/g"
869 # echoes the machine's hostname. can be used like so:
870 # local my_host=$(get_hostname)
871 function get_hostname()
873 # there used to be more variation in how to do this, but adopting mingw
874 # and cygwin tools really helped out.
875 local this_host=unknown
876 if [ "$OS" == "Windows_NT" ]; then
877 this_host=$(hostname)
878 elif [ ! -z "$(echo $MACHTYPE | grep apple)" ]; then
879 this_host=$(hostname)
880 elif [ ! -z "$(echo $MACHTYPE | grep suse)" ]; then
881 this_host=$(hostname --long)
882 elif [ -x "$(which hostname 2>/dev/null)" ]; then
883 this_host=$(hostname)
888 # makes sure that the provided "folder" is a directory and is writable.
889 function test_writeable()
891 local folder="$1"; shift
892 if [ ! -d "$folder" -o ! -w "$folder" ]; then return 1; fi
898 # given a filename and a string to seek and a number of lines, then this
899 # function will remove the first occurrence of a line in the file that
900 # matches the string, and it will also axe the next N lines as specified.
901 function create_chomped_copy_of_file()
903 local filename="$1"; shift
904 local seeker="$1"; shift
905 local numlines=$1; shift
907 #echo into create_chomped_copy...
908 #var filename seeker numlines
910 # make a backup first, oy.
911 \cp -f "$filename" "/tmp/$(basename ${filename}).bkup-${RANDOM}"
912 exit_on_error "backing up file: $filename"
914 # make a temp file to write to before we move file into place in bind.
915 local new_version="/tmp/$(basename ${filename}).bkup-${RANDOM}"
916 \rm -f "$new_version"
917 exit_on_error "cleaning out new version of file from: $new_version"
923 # don't bother looking at the lines if we're already in skip mode.
924 if [[ $skip_count == 0 ]]; then
925 # find the string they're seeking.
926 if [[ ! "$line" =~ .*${seeker}.* ]]; then
928 echo "$line" >> "$new_version"
930 # a match! start skipping. we will delete this line and the next N lines.
932 #echo first skip count is now $skip_count
936 # we're already skipping. let's keep going until we hit the limit.
938 #echo ongoing skip count is now $skip_count
939 if (( $skip_count > $numlines )); then
940 echo "Done skipping, and back to writing output file."
946 #echo file we created looks like this:
949 if [ ! -z "$found_any" ]; then
950 # put the file back into place under the original name.
951 \mv "$new_version" "$filename"
952 exit_on_error "moving the new version into place in: $filename"
954 # cannot always be considered an error, but we can at least gripe.
955 echo "Did not find any matches for seeker '$seeker' in file: $filename"
961 # space 'em all: fixes naming for all of the files of the appropriate types
962 # in the directories specified.
963 function spacemall() {
964 local -a dirs=("${@}")
965 if [ ${#dirs[@]} -eq 0 ]; then
969 local charnfile="$(mktemp $TMP/zz_charn.XXXXXX)"
970 find "${dirs[@]}" -follow -maxdepth 1 -mindepth 1 -type f | \
972 "doc\|docx\|eml\|html\|jpeg\|jpg\|m4a\|mov\|mp3\|ods\|odt\|pdf\|png\|ppt\|pptx\|txt\|vsd\|vsdx\|xls\|xlsx\|zip" | \
973 sed -e 's/^/"/' | sed -e 's/$/"/' | \
974 xargs bash "$FEISTY_MEOW_SCRIPTS/files/spacem.sh"
975 # drop the temp file now that we're done.
981 # site avenger aliases
984 THISDIR="$FEISTY_MEOW_SCRIPTS/site_avenger"
985 source "$FEISTY_MEOW_SCRIPTS/site_avenger/shared_site_mgr.sh"
991 # NOTE: no more function definitions are allowed after this point.
993 function function_sentinel()
998 if [ ! -z "$DEBUG_FEISTY_MEOW" ]; then echo "feisty meow function definitions done."; fi
1002 # test code for set_var_if_undefined.
1004 if [ $run_test != 0 ]; then
1005 echo running tests on set_var_if_undefined.
1007 set_var_if_undefined flagrant forknordle
1008 exit_on_error "testing if defined variable would be whacked"
1009 if [ $flagrant != petunia ]; then
1010 echo set_var_if_undefined failed to leave the test variable alone
1013 unset bobblehead_stomper
1014 set_var_if_undefined bobblehead_stomper endurance
1015 if [ $bobblehead_stomper != endurance ]; then
1016 echo set_var_if_undefined failed to set a variable that was not defined yet