#!/bin/bash # Global bash customization settings # Copyright (C) 2018 Pekka Helenius # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . ############################################################################## # In order to use this file, replace the following line in /etc/bash.bashrc file: # PS1="[\\u@\\h \\W]\\$ " # # with # # [[ -f /etc/bash.custom ]] && . /etc/bash.custom || PS1="[\\u@\\h \\W]\\$ " # Insert/Install this file into /etc folder. # After that, you can change bash settings globally by editing /etc/bash.custom file ############################################################################## # Check https://www.cyberciti.biz/tips/howto-linux-unix-bash-shell-setup-prompt.html for more settings ####################################### # Use server environment settings? Main switch. # Use only if you implement this solution to a server environment # You don't need this feature for client/local computers ENABLE_SERVER_ENV=no ####################################### # APPLIES ONLY IF SERVER ENVIRONMENT ENABLED # Retrieve time zone information for every user connected with a SSH client # Based on a look up for local GeoIP database # If timezone can't be defined, use UTC time as a fallback value # Timezone information can be overwritten by exporting TZ variable with # desirable value as the user in the user-specific $HOME/.bashrc file # # This method doesn't require any environment variables delivered via SSH # connection by a client # This method doesn't require any modifications to /etc/ssh/sshd_config file. # ENABLE_SSH_TIMEZONE=yes ####################################### # APPLIES ONLY IF SERVER ENVIRONMENT ENABLED # If server environment is enabled if [[ $ENABLE_SERVER_ENV == "yes" ]]; then if [[ $ENABLE_SSH_TIMEZONE == "yes" ]]; then if [[ $(export -p | grep SSH_TTY) ]]; then . $(which ssh_timezone) fi fi fi ############################################################################## # Hook to bash's STDERR output so that it will be printed as red for all users export LD_PRELOAD="/usr/\$LIB/libstderred.so${LD_PRELOAD:+:$LD_PRELOAD}" ############################################################################## # COLOR TABLE # These are available colors # Expand if you wish # Full color table available by executing 'tputcolors' command # To get equal color values here, use command 'tput setaf | hexdump -c' # By default, blank TTY sessions have TERM=linux, which has limitation of 8 possible colors when # tput is used. On many graphical environments, TERM=xterm-256color is used instead, expanding # all possible colors to 256. # Because colors defined in this bash file rely on 256 color support, we must # export TERM=xterm-256color in all opened shell sessions, including blank TTYs. # # Setting raw color values, which are disabled below, does not work well with # slash \$ escaped 'bash_foldercolor' function (defined below) # # You get count of supported colors with 'tput colors' command # export TERM=xterm-256color bash_red=$(tput setaf 196) bash_pink=$(tput setaf 211) bash_green=$(tput setaf 46) bash_yellow=$(tput setaf 226) bash_light_yellow=$(tput setaf 229) bash_gold=$(tput setaf 184) bash_orange=$(tput setaf 172) bash_blue=$(tput setaf 27) bash_light_blue=$(tput setaf 33) bash_magenta=$(tput setaf 201) bash_cyan=$(tput setaf 51) bash_turquoise=$(tput setaf 86) bash_grey=$(tput setaf 250) bash_white=$(tput setaf 255) bash_color_default=$(tput sgr0) #bash_red="\033[38;5;196m" #bash_pink="\033[38;5;211" #bash_green="\033[38;5;46m" #bash_yellow="\033[38;5;226m" #bash_light_yellow="\033[38;5;229m" #bash_gold="\033[38;5;184m" #bash_orange="\033[38;5;172m" #bash_blue="\033[38;5;27m" #bash_light_blue="\033[38;5;33m" #bash_magenta="\033[38;5;201m" #bash_cyan="\033[38;5;51m" #bash_turquoise="\033[38;5;86m" #bash_grey="\033[38;5;250m" #bash_white="\033[38;5;255m" #bash_color_default="\033[0m" ############################################################################## # COLOR TABLE CHECK FUNCTION bash_colorstring() { case $1 in red) printf "\x01%s\x02" "${bash_red}" ;; pink) printf "\x01%s\x02" "${bash_pink}" ;; green) printf "\x01%s\x02" "${bash_green}" ;; yellow) printf "\x01%s\x02" "${bash_yellow}" ;; light_yellow) printf "\x01%s\x02" "${bash_light_yellow}" ;; gold) printf "\x01%s\x02" "${bash_gold}" ;; orange) printf "\x01%s\x02" "${bash_orange}" ;; blue) printf "\x01%s\x02" "${bash_blue}" ;; light_blue) printf "\x01%s\x02" "${bash_light_blue}" ;; magenta|purple) printf "\x01%s\x02" "${bash_magenta}" ;; cyan) printf "\x01%s\x02" "${bash_cyan}" ;; turquoise) printf "\x01%s\x02" "${bash_turquoise}" ;; grey) printf "\x01%s\x02" "${bash_grey}" ;; white) printf "\x01%s\x02" "${bash_white}" ;; default|*) printf "\x01%s\x02" "${bash_color_default}" esac } ############################################################################## # Original PS1 variable value #PS1='[\u@\h \W]\$ ' ####################################### # APPLIES ONLY IF SERVER ENVIRONMENT ENABLED # Different command prompt for local (server) logins? # Distinguish from SSH logins # This string does not have any colors for now # Applies only to tty sessions (sessions without X desktop) BASH_PS1_DIFFERENT_LOCAL=yes BASH_PS1_LOCAL='[\u: \W ]\$ ' ####################################### # This is an override switch for all color settings BASH_PS1_SHOW_COLORS=yes ####################################### # Start and ending symbols for command prompt BASH_PS1_START="[" BASH_PS1_START_COLORS=no BASH_PS1_START_COLOR=$(bash_colorstring default) BASH_PS1_END=" ]" BASH_PS1_END_COLORS=no BASH_PS1_END_COLOR=$(bash_colorstring default) ####################################### # Override command prompt string? BASH_PS1_SYNTAX_OVERRIDE=no BASH_PS1_SYNTAX_OVERRIDESTR='[\u@\h \W]\$ ' ####################################### # Use colors for users? # Group 'sudo' members are considered as sysadmins. BASH_USER_COLORS=yes BASH_SYSADMIN_COLOR=$(bash_colorstring yellow) BASH_USER_COLOR=$(bash_colorstring default) BASH_ROOT_COLOR=$(bash_colorstring red) ####################################### # Use different color for folders owned by the user and some other color for other folders? BASH_FOLDER_COLORS=yes BASH_USER_FOLDER_COLOR=$(bash_colorstring green) BASH_NOTOWNED_FOLDER_COLOR=$(bash_colorstring red) ####################################### # Colors for ls command? BASH_LS_COLORS=yes ####################################### # Show the name of this computer? BASH_SHOW_HOSTNAME=no # User and hostname separator settings BASH_HOSTNAME_SEP="@" BASH_HOSTNAME_SEP_COLORS=no BASH_HOSTNAME_SEP_COLOR=$(bash_colorstring gold) # Use color for hostname? BASH_HOSTNAME_COLORS=yes BASH_HOSTNAME_COLOR=$(bash_colorstring blue) ####################################### # Hostname/user and folder separator settings BASH_FOLDER_SEP=":" BASH_FOLDER_SEP_COLORS=no BASH_FOLDER_SEP_COLOR=$(bash_colorstring default) ####################################### # Suffix symbol settings BASH_SUFFIX_SYMBOL="$ " BASH_SUFFIX_SYMBOL_ROOT="# " BASH_SUFFIX_COLORS=no BASH_SUFFIX_COLOR=$(bash_colorstring default) ############################################################################## # Timestamp # Show timestamp in the command prompt? BASH_SHOW_TIMESTAMP=yes # Example: 26/02/2018 21:33:19 # "\D{%d/%m/%Y} \t" # Example: 26/02/2018 # "\D{%d/%m/%Y}" # Example: 21:33:19 # "\t" BASH_TIMESTAMP_FORMAT=" \! | \D{%d/%m/%Y} \t" BASH_TIMESTAMP_COLORS=no BASH_TIMESTAMP_COLOR=$(bash_colorstring default) ####################################### # Return codes after command execution # Show command return code in bash? USE_RETCODE=yes # Print human readable text strings for each code? RETCODE_HUMAN=no # Use colors in error codes? RETCODE_COLORS=yes if [[ $USE_RETCODE == "yes" ]]; then function RETCODE() { local RET=$? case $RET in 0) local RETC=$(bash_colorstring green) local RETH="ok" ;; 1) local RETC=$(bash_colorstring red) local RETH="error" ;; 2) local RETC=$(bash_colorstring orange) local RETH="misuse of shell builtin" ;; 127) local RETC=$(bash_colorstring orange) local RETH="not found" ;; 128) local RETC=$(bash_colorstring red) local RETH="invalid exit argument" ;; 130) local RETC=$(bash_colorstring purple) local RETH="aborted" ;; *) local RETC=$(bash_colorstring yellow) local RETH="undefined exit code" ;; esac if [[ $RETCODE_COLORS == "no" ]]; then RETC=$(bash_colorstring default) fi if [[ $RETCODE_HUMAN == "yes" ]]; then printf "Return code: ${RETC}$RET - $RETH$(bash_colorstring default)\n" else printf "Return code: ${RETC}$RET$(bash_colorstring default)\n" fi } PROMPT_COMMAND=RETCODE fi ############################################################################## # Set up ls command colors # if [[ $BASH_PS1_SHOW_COLORS == "yes" ]]; then if [[ $BASH_LS_COLORS == "yes" ]]; then eval "$(dircolors -b /etc/dircolors)" alias ls='ls --color=auto' fi fi ####################################### # Set up starting and ending symbols # if [[ $BASH_PS1_START_COLORS == "yes" ]]; then BASH_PS1_START_INSERT="${BASH_PS1_START_COLOR}${BASH_PS1_START}$(bash_colorstring default)" else BASH_PS1_START_INSERT="${BASH_PS1_START}" fi if [[ $BASH_PS1_END_COLORS == "yes" ]]; then BASH_PS1_END_INSERT="${BASH_PS1_END_COLOR}${BASH_PS1_END}$(bash_colorstring default)" else BASH_PS1_END_INSERT="${BASH_PS1_END}" fi ####################################### # Set up folder-specific colors # bash_foldercolor() { # Change color if we are not owner of the current dir # For root we always use green color # if [[ $BASH_FOLDER_COLORS == "yes" ]]; then if [[ $(stat -c %u "$PWD") -eq $(id -u) ]] || [[ $(id -u) -eq 0 ]]; then # Green color printf "%s" "${BASH_USER_FOLDER_COLOR}" else # Red color printf "%s" "${BASH_NOTOWNED_FOLDER_COLOR}" fi else # White color // reset attributes printf "%s" "$(bash_colorstring default)" fi } ####################################### # Set up user-specific colors # bash_usercolor() { if [[ $BASH_USER_COLORS == "yes" ]] ;then if [[ $(id -u) == 0 ]]; then printf "%s" "${BASH_ROOT_COLOR}" elif [[ $(groups | grep -o sudo) ]]; then printf "%s" "${BASH_SYSADMIN_COLOR}" else printf "%s" "${BASH_USER_COLOR}" fi else printf "%s" "$(bash_colorstring default)" fi } ####################################### # Set up computer hostname # bash_hostname() { if [[ $BASH_SHOW_HOSTNAME == "yes" ]]; then if [[ $BASH_HOSTNAME_SEP_COLORS == "yes" ]]; then BASH_HOSTNAME_SEP_INSERT="${BASH_HOSTNAME_SEP_COLOR}${BASH_HOSTNAME_SEP}$(bash_colorstring default)" else BASH_HOSTNAME_SEP_INSERT="${BASH_HOSTNAME_SEP}" fi if [[ $BASH_HOSTNAME_COLORS == "yes" ]]; then printf "%s" "\u$(bash_colorstring default)${BASH_HOSTNAME_SEP_INSERT}${BASH_HOSTNAME_COLOR}\h$(bash_colorstring default)" else printf "%s" "\u$(bash_colorstring default)${BASH_HOSTNAME_SEP_INSERT}\h" fi else printf "%s" "\u$(bash_colorstring default)" fi } ####################################### # Set up folder separator # bash_folder_separator() { if [[ $BASH_FOLDER_SEP_COLORS == "yes" ]] && [[ $BASH_SHOW_HOSTNAME == "yes" ]]; then printf "%s" "${BASH_FOLDER_SEP_COLOR}${BASH_FOLDER_SEP}$(bash_colorstring default)" else printf "%s" "${BASH_FOLDER_SEP}" fi } ####################################### # Set up timestamp # bash_timestamp() { if [[ $BASH_SHOW_TIMESTAMP == "yes" ]]; then if [[ $BASH_TIMESTAMP_COLORS == "yes" ]]; then printf "%s" "${BASH_TIMESTAMP_COLOR}${BASH_TIMESTAMP_FORMAT}$(bash_colorstring default) - " else printf "%s" "${BASH_TIMESTAMP_FORMAT} - " fi else printf "" fi } ####################################### # Set up suffix symbol # bash_suffixsymbol() { if [[ $(id -u) -eq 0 ]]; then BASH_SUFFIX=${BASH_SUFFIX_SYMBOL_ROOT} else BASH_SUFFIX=${BASH_SUFFIX_SYMBOL} fi if [[ $BASH_SUFFIX_COLORS == "yes" ]]; then printf "%s" "${BASH_SUFFIX_COLOR}${BASH_SUFFIX}$(bash_colorstring default)" else printf "%s" "${BASH_SUFFIX}" fi } ####################################### # Export command prompt string # if [[ $BASH_PS1_SHOW_COLORS != "yes" ]]; then BASH_PS1_START_COLORS=$(bash_colorstring default) BASH_PS1_END_COLORS=$(bash_colorstring default) BASH_USER_COLOR=$(bash_colorstring default) BASH_ROOT_COLOR=$(bash_colorstring default) BASH_USER_FOLDER_COLOR=$(bash_colorstring default) BASH_NOTOWNED_FOLDER_COLOR=$(bash_colorstring default) BASH_HOSTNAME_COLOR=$(bash_colorstring default) BASH_SUFFIX_COLOR=$(bash_colorstring default) BASH_TIMESTAMP_COLOR=$(bash_colorstring default) fi ps1_syntax() { # Default string export PS1="$BASH_PS1_START_INSERT$(bash_timestamp)$(bash_usercolor)$(bash_hostname)$(bash_folder_separator) \$(bash_foldercolor)\W$(bash_colorstring default)$BASH_PS1_END_INSERT$(bash_suffixsymbol)" } if [[ $BASH_PS1_SYNTAX_OVERRIDE == "no" ]]; then # If we want to use different PS1 variable for local logins... if [[ $BASH_PS1_DIFFERENT_LOCAL == "yes" ]] && [[ $ENABLE_SERVER_ENV == "yes" ]]; then # Check if we are local login... # Returns 0 (true) if we are, otherwise 1 (false) if [[ ! $(export -p | grep SSH_TTY) ]]; then export PS1=${BASH_PS1_LOCAL} else ps1_syntax fi else ps1_syntax fi elif [[ $BASH_PS1_SYNTAX_OVERRIDE == "yes" ]]; then # User override string export PS1=${BASH_PS1_SYNTAX_OVERRIDESTR} else # Fallback string export PS1='[\u@\h \W]\$ ' fi ############################################################################## # Common messages for sudo checks # # Ask password every time for sudo commands? SUDO_ASKPASS=yes # Separator function INFO_SEP() { # http://wiki.bash-hackers.org/snipplets/print_horizontal_line#a_line_across_the_entire_width_of_the_terminal printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - } # Default information printed to user INFO_MSG="\ $(bash_colorstring orange)\ Privileged permissions required\ $(bash_colorstring default)\ " # # If any of the following messages is printed by a command, # then try the command with sudo prefix ERROR_MSGS="\ Permission denied|\ Operation not permitted|\ you cannot perform this operation unless you are root|\ You may not view or modify password information for root\ " ####################################### # Check if the current user belongs to sudo # or is root # sudocheck() { if [[ $UID -ne 0 ]]; then if [[ ! $(printf $(groups | grep sudo &> /dev/null)$?) -eq 0 ]]; then printf "Current user does not have sufficient permissions and does not belong to 'sudo' group.\n" return 1 else if [[ $SUDO_ASKPASS == "yes" ]]; then sudo -k fi return 0 fi else return 0 fi } ####################################### # Execute with sudo if no permissions # to execute a command otherwise # # NOTE: This does not work for nano or cd commands # function sudoperms() { # Previous command (ERR) always returns value 1 which is not # we don't want if the following sudo command succeeds # unset PROMPT_COMMAND local CMD="${BASH_COMMAND}" # WORKAROUND # rm command has an interactive prompt where # it asks for confirmation for file deletion # However, interactive prompt does not work # very well here, thus we hook --force/-f # option to the original rm command # if [[ "${CMD}" =~ ^rm[[:space:]] ]]; then CMD=$(printf "${CMD}" | sed -E 's/^rm/rm -f/') fi if [[ $(${CMD} 2>&>1 > /dev/null | grep -E "${ERROR_MSGS}") ]]; then printf "${INFO_MSG}\n" sudocheck if [[ $? -eq 0 ]]; then INFO_SEP # Execute the failed command with sudo and get its return code sudo bash -c "${CMD}" && RETCODE fi fi checkdone= } if [[ -z checkdone ]]; then trap 'sudoperms' ERR fi ####################################### # If nano doesn't have correct permissions, use sudo # automatically for it # sudonano() { # Prevent file names having spaces to be splitted up to # multiple arguments by setting local IFS variable to be # a newline instead of space # local IFS=$'\n' # Get all input arguments into a new array local i=0 for arg in "${@}"; do ARGS[$i]="${arg}" let i++ done # If the first argument is not -h or --help, apply other arguments, too # if [[ "${1}" != "-h" ]] || [[ "${1}" != "--help" ]]; then # If the last input argument is a file, delete # it from the existing ARGS array # and put it into a new variable FILE . # Check owner of the file # # If no input file is given, treat # all arguments as options for nano editor # if [[ -f "${ARGS[-1]}" ]]; then # Get full file path (e.g. if user types just # name of a file in the current folder) local FILE=$(readlink -f "${ARGS[-1]}") # Set single quotes around the file name with full path # This is just for stat command below # local FILE=$(printf "${FILE}" | sed "s/\(.*\)\r/'\1'/g") local OWNER=$(stat -c %u "${FILE}") # Remove filename from the arguments list since it # is not actually an argument we want to supply to # nano. We need to treat the filename in a special # way unlike other arguments # unset 'ARGS[${#ARGS[@]}-1]' # Add escape prefixes to every whitespace we have # in the filename because single quotes are # not well preserved when supplying filename # to nano command # if [[ "${FILE}" =~ [[:space:]] ]]; then FILE=$(printf "${FILE}" | sed 's/ /\\ /g') fi # If arguments were given, put them before # the filename. If no arguments were given, # just supply the filename to nano command # if [[ -n ${ARGS[*]} ]]; then local OPTIONS="${ARGS[*]} ${FILE}" else local OPTIONS="${FILE}" fi else local OPTIONS="${ARGS[*]}" fi else local OPTIONS="${1}" fi if [[ $UID -ne 0 ]]; then if [[ -v OWNER ]]; then if [[ $OWNER -ne $UID ]]; then printf "${INFO_MSG}\n" sudocheck if [[ $? -eq 0 ]]; then INFO_SEP sudo nano ${OPTIONS} fi else nano ${OPTIONS} fi else nano ${OPTIONS} fi else nano ${OPTIONS} fi # In a case of failure (e.g. return code 1) # we want to get the real code number # That's why we call RETCODE function # which returns the right value for # the previous command # RETCODE # We need to unset PROMPT_COMMAND variable # after RETCODE function execution # Otherwise we get false-positive # return value (return code 0) for # the previous command, no matter # whether it succeeded or failed # unset PROMPT_COMMAND } if [[ $(printf $(which nano &> /dev/null)$?) -eq 0 ]]; then alias nano='sudonano' fi ####################################### # If find doesn't have correct permissions, use sudo # automatically for it # : ' sudofind() { if [[ ! "${1}" =~ ^-{1,2}[a-z]* ]]; then if [[ ! -d "${1}" ]]; then printf "$(bash_colorstring red)Error:$(bash_colorstring default) ${1}: No such directory\n" return 1 fi else find "${1}" fi if [[ $UID -ne 0 ]]; then local i=0 for arg in "${@}"; do if [[ $arg =~ [[:space:]] ]]; then arg=\"$arg\" fi local ARGS[$i]="${arg}" let i++ done local DIRPATH="${ARGS[0]}" local OWNER_STR=$(stat -c %U "${DIRPATH}") local USER_STR=$(id -un $UID) if [[ $OWNER_STR == $USER_STR ]]; then find "${ARGS[*]}" else sudo SUDOARGS="${ARGS[*]}" -u $OWNER_STR bash -c 'find "${SUDOARGS}"' fi else find "${ARGS[*]}" fi } alias find='sudofind' ' ####################################### # If we don't have access to a directory, check dir owner # and access the folder as that user with sudo # sudocd() { if [[ -d "${1}" ]]; then if [[ $UID -ne 0 ]]; then if [[ $(stat -c %u "${1}") -ne $UID ]]; then local PERMS=$(stat -c %A "${1}") if [[ $(echo "${PERMS:9:1}") =~ x|t ]]; then cd "${1}" else printf "${INFO_MSG}\n" sudocheck if [[ $? -eq 0 ]]; then INFO_SEP local OWNER=$(stat -c %U "${1}") printf "Opening $OWNER shell environment\n" sudo GODIR="${1}" -u $OWNER bash -c 'cd "${GODIR}"; $SHELL' fi fi else cd "${1}" fi else cd "${1}" fi elif [[ -z "${1}" ]]; then cd "${HOME}" else printf "$(bash_colorstring red)Error:$(bash_colorstring default) No such directory\n" return 1 fi } alias cd='sudocd'