Bash
‘.~/.bashrc’ 沒有在呼叫腳本中按預期設置變數
背景
我已經編寫了一個腳本來
node
通過nvm
.問題
. $LOCAL_SHELL_CONFIG_FILE
裡面的命令install_latest_stable_node()
不會執行,因此,當它列印node
和npm
(echo "$(which node)" && echo "$(which npm)"
) 的 PATH 時,它會列印兩個空行。一旦腳本終止,我就可以執行
. ~/.bashrc
,然後執行,echo "$(which node)" && echo "$(which npm)"
這將回顯 PATH,這次沒有兩個空行。為什麼?
程式碼
#!/bin/bash ask_for_sudo() { # Ask for the administrator password upfront. sudo -v &> /dev/null # Update existing `sudo` time stamp # until this script has finished. # # https://gist.github.com/cowboy/3118588 while true; do sudo -n true sleep 60 kill -0 "$$" || exit done &> /dev/null & } show_spinner() { local -r FRAMES='/-\|' # shellcheck disable=SC2034 local -r NUMBER_OR_FRAMES=${#FRAMES} local -r CMDS="$2" local -r MSG="$3" local -r PID="$1" local i=0 local frameText="" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Note: In order for the Travis CI site to display # things correctly, it needs special treatment, hence, # the "is Travis CI?" checks. if [ "$TRAVIS" != "true" ]; then # Provide more space so that the text hopefully # doesn't reach the bottom line of the terminal window. # # This is a workaround for escape sequences not tracking # the buffer position (accounting for scrolling). # # See also: https://unix.stackexchange.com/a/278888 printf "\n\n\n" tput cuu 3 tput sc fi # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Display spinner while the commands are being executed. while kill -0 "$PID" &>/dev/null; do frameText=" [${FRAMES:i++%NUMBER_OR_FRAMES:1}] $MSG" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Print frame text. if [ "$TRAVIS" != "true" ]; then printf "%s\n" "$frameText" else printf "%s" "$frameText" fi sleep 0.2 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Clear frame text. if [ "$TRAVIS" != "true" ]; then tput rc else printf "\r" fi done } execute() { local -r CMDS="$1" local -r MSG="$2" local -r TMP_FILE="$(mktemp /tmp/XXXXX)" local exitCode=0 local cmdsPID="" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # If the current process is ended, # also end all its subprocesses. set_trap "EXIT" "kill_all_subprocesses" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Execute commands in background eval "$CMDS" \ &> /dev/null \ 2> "$TMP_FILE" & cmdsPID=$! # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Show a spinner if the commands # require more time to complete. show_spinner "$cmdsPID" "$CMDS" "$MSG" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Wait for the commands to no longer be executing # in the background, and then get their exit code. wait "$cmdsPID" &> /dev/null exitCode=$? # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Print output based on what happened. print_result $exitCode "$MSG" if [ $exitCode -ne 0 ]; then print_error_stream < "$TMP_FILE" fi rm -rf "$TMP_FILE" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - return $exitCode } set_trap() { trap -p "$1" | grep "$2" &> /dev/null \ || trap '$2' "$1" } print_error_stream() { while read -r line; do print_error "↳ ERROR: $line" done } print_error() { print_in_red " [✖] $1 $2\n" } print_success() { print_in_green " [✔] $1\n" } print_in_red() { print_in_color "$1" 1 } print_in_green() { print_in_color "$1" 2 } print_in_purple() { print_in_color "$1" 5 } print_in_color() { printf "%b" \ "$(tput setaf "$2" 2> /dev/null)" \ "$1" \ "$(tput sgr0 2> /dev/null)" } print_result() { if [ "$1" -eq 0 ]; then print_success "$2" else print_error "$2" fi return "$1" } fix_dpkg() { declare -a files=("/var/lib/dpkg/lock" "/var/cache/apt/archives/" "/var/cache/apt/archives/lock") for i in "${files[@]}" do # If there is a dpkg lock, then remove it. if [ -e "$i" ]; then sudo rm -rf "$i" &> /dev/null fi done } install_package() { declare -r PACKAGE="$2" declare -r PACKAGE_READABLE_NAME="$1" if ! package_is_installed "$PACKAGE"; then fix_dpkg execute "sudo apt-get install --allow-unauthenticated -qqy $PACKAGE" "$PACKAGE_READABLE_NAME" # suppress output ─┘│ # assume "yes" as the answer to all prompts ──┘ else print_success "$PACKAGE_READABLE_NAME" fi } package_is_installed() { dpkg -s "$1" &> /dev/null } install_nvm() { # Install `nvm` and add the necessary # configs in the local shell config file. # One-liner: # wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | PROFILE=~/.bash.local bash && . ~/.bash.local execute \ "wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | \ PROFILE=$LOCAL_SHELL_CONFIG_FILE NVM_DIR=$NVM_DIRECTORY bash" \ "nvm (install)" } update_nvm() { execute \ "cd $NVM_DIRECTORY \ && git fetch --quiet origin \ && git checkout --quiet \$(git describe --abbrev=0 --tags) \ && . $NVM_DIRECTORY/nvm.sh" \ "nvm (upgrade)" } install_latest_stable_node() { # Install the latest stable version of Node # (this will also set it as the default). # One-liner: #. ~/.bash.local && nvm install node . $LOCAL_SHELL_CONFIG_FILE execute \ "source $LOCAL_SHELL_CONFIG_FILE \ && nvm install node" \ "nvm (install latest Node)" } main() { ask_for_sudo touch "$LOCAL_SHELL_CONFIG_FILE" print_in_purple "\n Dependencies\n\n" install_package "git" "git" print_in_purple "\n nvm\n\n" if [ -d "$NVM_DIRECTORY" ]; then rm -rf "$NVM_DIRECTORY" fi install_nvm update_nvm install_latest_stable_node print_in_purple "\n PATHs\n\n" echo "$(which node)" echo "$(which npm)" } declare -r LOCAL_SHELL_CONFIG_FILE="$HOME/.bashrc" declare -r NVM_DIRECTORY="$HOME/.nvm" main
您的腳本正在獲取指定的文件。
您看到兩個空行而不是預期的路徑名的原因是腳本
$LOCAL_SHELL_CONFIG_FILE
從您的“”函式內部獲取原始碼execute()
,該函式在後台(即在子外殼中)執行命令。子shell 不能修改父shell 的環境。