github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/docker/library-scripts/common-debian.sh (about) 1 #!/usr/bin/env bash 2 #------------------------------------------------------------------------------------------------------------- 3 # Copyright (c) Microsoft Corporation. All rights reserved. 4 # Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. 5 #------------------------------------------------------------------------------------------------------------- 6 # 7 # Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/common.md 8 # Maintainer: The VS Code and Codespaces Teams 9 # 10 # Syntax: ./common-debian.sh [install zsh flag] [username] [user UID] [user GID] [upgrade packages flag] [install Oh My Zsh! flag] [Add non-free packages] 11 12 set -e 13 14 INSTALL_ZSH=${1:-"true"} 15 USERNAME=${2:-"automatic"} 16 USER_UID=${3:-"automatic"} 17 USER_GID=${4:-"automatic"} 18 UPGRADE_PACKAGES=${5:-"true"} 19 INSTALL_OH_MYS=${6:-"true"} 20 ADD_NON_FREE_PACKAGES=${7:-"false"} 21 SCRIPT_DIR="$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)" 22 MARKER_FILE="/usr/local/etc/vscode-dev-containers/common" 23 24 if [ "$(id -u)" -ne 0 ]; then 25 echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' 26 exit 1 27 fi 28 29 # Ensure that login shells get the correct path if the user updated the PATH using ENV. 30 rm -f /etc/profile.d/00-restore-env.sh 31 echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh 32 chmod +x /etc/profile.d/00-restore-env.sh 33 34 # If in automatic mode, determine if a user already exists, if not use vscode 35 if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then 36 USERNAME="" 37 POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)") 38 for CURRENT_USER in ${POSSIBLE_USERS[@]}; do 39 if id -u ${CURRENT_USER} > /dev/null 2>&1; then 40 USERNAME=${CURRENT_USER} 41 break 42 fi 43 done 44 if [ "${USERNAME}" = "" ]; then 45 USERNAME=vscode 46 fi 47 elif [ "${USERNAME}" = "none" ]; then 48 USERNAME=root 49 USER_UID=0 50 USER_GID=0 51 fi 52 53 # Load markers to see which steps have already run 54 if [ -f "${MARKER_FILE}" ]; then 55 echo "Marker file found:" 56 cat "${MARKER_FILE}" 57 source "${MARKER_FILE}" 58 fi 59 60 # Ensure apt is in non-interactive to avoid prompts 61 export DEBIAN_FRONTEND=noninteractive 62 63 # Function to call apt-get if needed 64 apt_get_update_if_needed() 65 { 66 if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then 67 echo "Running apt-get update..." 68 apt_switch_mirror_site 69 apt-get update 70 else 71 echo "Skipping apt-get update." 72 fi 73 } 74 75 # Replace Debian APT mirror sites. 76 apt_switch_mirror_site() 77 { 78 if [ ! -z "$DEBIAN_MIRROR" ]; then 79 sed -i -E "s/(deb|1|security)\.debian\.org/$DEBIAN_MIRROR/g" /etc/apt/sources.list 80 fi 81 } 82 83 # Run install apt-utils to avoid debconf warning then verify presence of other common developer tools and dependencies 84 if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then 85 86 package_list="apt-utils \ 87 openssh-client \ 88 gnupg2 \ 89 dirmngr \ 90 iproute2 \ 91 procps \ 92 lsof \ 93 htop \ 94 net-tools \ 95 psmisc \ 96 curl \ 97 wget \ 98 rsync \ 99 ca-certificates \ 100 unzip \ 101 zip \ 102 nano \ 103 vim-tiny \ 104 less \ 105 jq \ 106 lsb-release \ 107 apt-transport-https \ 108 dialog \ 109 libc6 \ 110 libgcc1 \ 111 libkrb5-3 \ 112 libgssapi-krb5-2 \ 113 libicu[0-9][0-9] \ 114 liblttng-ust[0-9] \ 115 libstdc++6 \ 116 zlib1g \ 117 locales \ 118 sudo \ 119 ncdu \ 120 man-db \ 121 strace \ 122 manpages \ 123 manpages-dev \ 124 init-system-helpers" 125 126 # Needed for adding manpages-posix and manpages-posix-dev which are non-free packages in Debian 127 if [ "${ADD_NON_FREE_PACKAGES}" = "true" ]; then 128 # Bring in variables from /etc/os-release like VERSION_CODENAME 129 . /etc/os-release 130 sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list 131 sed -i -E "s/deb-src http:\/\/(deb|httredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list 132 sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list 133 sed -i -E "s/deb-src http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list 134 sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list 135 sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list 136 sed -i "s/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list 137 sed -i "s/deb-src http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list 138 # Handle bullseye location for security https://www.debian.org/releases/bullseye/amd64/release-notes/ch-information.en.html 139 sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list 140 sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list 141 echo "Running apt-get update..." 142 apt_switch_mirror_site 143 apt-get update 144 package_list="${package_list} manpages-posix manpages-posix-dev" 145 else 146 apt_get_update_if_needed 147 fi 148 149 # Install libssl1.1 if available 150 if [[ ! -z $(apt-cache --names-only search ^libssl1.1$) ]]; then 151 package_list="${package_list} libssl1.1" 152 fi 153 154 # Install appropriate version of libssl1.0.x if available 155 libssl_package=$(dpkg-query -f '${db:Status-Abbrev}\t${binary:Package}\n' -W 'libssl1\.0\.?' 2>&1 || echo '') 156 if [ "$(echo "$LIlibssl_packageBSSL" | grep -o 'libssl1\.0\.[0-9]:' | uniq | sort | wc -l)" -eq 0 ]; then 157 if [[ ! -z $(apt-cache --names-only search ^libssl1.0.2$) ]]; then 158 # Debian 9 159 package_list="${package_list} libssl1.0.2" 160 elif [[ ! -z $(apt-cache --names-only search ^libssl1.0.0$) ]]; then 161 # Ubuntu 18.04, 16.04, earlier 162 package_list="${package_list} libssl1.0.0" 163 fi 164 fi 165 166 echo "Packages to verify are installed: ${package_list}" 167 apt-get -y install --no-install-recommends ${package_list} 2> >( grep -v 'debconf: delaying package configuration, since apt-utils is not installed' >&2 ) 168 169 # Install git if not already installed (may be more recent than distro version) 170 if ! type git > /dev/null 2>&1; then 171 apt-get -y install --no-install-recommends git 172 fi 173 174 PACKAGES_ALREADY_INSTALLED="true" 175 fi 176 177 # Get to latest versions of all packages 178 if [ "${UPGRADE_PACKAGES}" = "true" ]; then 179 apt_get_update_if_needed 180 apt-get -y upgrade --no-install-recommends 181 apt-get autoremove -y 182 fi 183 184 # Ensure at least the en_US.UTF-8 UTF-8 locale is available. 185 # Common need for both applications and things like the agnoster ZSH theme. 186 if [ "${LOCALE_ALREADY_SET}" != "true" ] && ! grep -o -E '^\s*en_US.UTF-8\s+UTF-8' /etc/locale.gen > /dev/null; then 187 echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen 188 locale-gen 189 LOCALE_ALREADY_SET="true" 190 fi 191 192 # Create or update a non-root user to match UID/GID. 193 group_name="${USERNAME}" 194 if id -u ${USERNAME} > /dev/null 2>&1; then 195 # User exists, update if needed 196 if [ "${USER_GID}" != "automatic" ] && [ "$USER_GID" != "$(id -g $USERNAME)" ]; then 197 group_name="$(id -gn $USERNAME)" 198 groupmod --gid $USER_GID ${group_name} 199 usermod --gid $USER_GID $USERNAME 200 fi 201 if [ "${USER_UID}" != "automatic" ] && [ "$USER_UID" != "$(id -u $USERNAME)" ]; then 202 usermod --uid $USER_UID $USERNAME 203 fi 204 else 205 # Create user 206 if [ "${USER_GID}" = "automatic" ]; then 207 groupadd $USERNAME 208 else 209 groupadd --gid $USER_GID $USERNAME 210 fi 211 if [ "${USER_UID}" = "automatic" ]; then 212 useradd -s /bin/bash --gid $USERNAME -m $USERNAME 213 else 214 useradd -s /bin/bash --uid $USER_UID --gid $USERNAME -m $USERNAME 215 fi 216 fi 217 218 # Add sudo support for non-root user 219 if [ "${USERNAME}" != "root" ] && [ "${EXISTING_NON_ROOT_USER}" != "${USERNAME}" ]; then 220 echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME 221 chmod 0440 /etc/sudoers.d/$USERNAME 222 EXISTING_NON_ROOT_USER="${USERNAME}" 223 fi 224 225 # ** Shell customization section ** 226 if [ "${USERNAME}" = "root" ]; then 227 user_rc_path="/root" 228 else 229 user_rc_path="/home/${USERNAME}" 230 fi 231 232 # Restore user .bashrc defaults from skeleton file if it doesn't exist or is empty 233 if [ ! -f "${user_rc_path}/.bashrc" ] || [ ! -s "${user_rc_path}/.bashrc" ] ; then 234 cp /etc/skel/.bashrc "${user_rc_path}/.bashrc" 235 fi 236 237 # Restore user .profile defaults from skeleton file if it doesn't exist or is empty 238 if [ ! -f "${user_rc_path}/.profile" ] || [ ! -s "${user_rc_path}/.profile" ] ; then 239 cp /etc/skel/.profile "${user_rc_path}/.profile" 240 fi 241 242 # .bashrc/.zshrc snippet 243 rc_snippet="$(cat << 'EOF' 244 245 if [ -z "${USER}" ]; then export USER=$(whoami); fi 246 if [[ "${PATH}" != *"$HOME/.local/bin"* ]]; then export PATH="${PATH}:$HOME/.local/bin"; fi 247 248 # Display optional first run image specific notice if configured and terminal is interactive 249 if [ -t 1 ] && [[ "${TERM_PROGRAM}" = "vscode" || "${TERM_PROGRAM}" = "codespaces" ]] && [ ! -f "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed" ]; then 250 if [ -f "/usr/local/etc/vscode-dev-containers/first-run-notice.txt" ]; then 251 cat "/usr/local/etc/vscode-dev-containers/first-run-notice.txt" 252 elif [ -f "/workspaces/.codespaces/shared/first-run-notice.txt" ]; then 253 cat "/workspaces/.codespaces/shared/first-run-notice.txt" 254 fi 255 mkdir -p "$HOME/.config/vscode-dev-containers" 256 # Mark first run notice as displayed after 10s to avoid problems with fast terminal refreshes hiding it 257 ((sleep 10s; touch "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed") &) 258 fi 259 260 # Set the default git editor if not already set 261 if [ -z "$(git config --get core.editor)" ] && [ -z "${GIT_EDITOR}" ]; then 262 if [ "${TERM_PROGRAM}" = "vscode" ]; then 263 if [[ -n $(command -v code-insiders) && -z $(command -v code) ]]; then 264 export GIT_EDITOR="code-insiders --wait" 265 else 266 export GIT_EDITOR="code --wait" 267 fi 268 fi 269 fi 270 271 EOF 272 )" 273 274 # code shim, it fallbacks to code-insiders if code is not available 275 cat << 'EOF' > /usr/local/bin/code 276 #!/bin/sh 277 278 get_in_path_except_current() { 279 which -a "$1" | grep -A1 "$0" | grep -v "$0" 280 } 281 282 code="$(get_in_path_except_current code)" 283 284 if [ -n "$code" ]; then 285 exec "$code" "$@" 286 elif [ "$(command -v code-insiders)" ]; then 287 exec code-insiders "$@" 288 else 289 echo "code or code-insiders is not installed" >&2 290 exit 127 291 fi 292 EOF 293 chmod +x /usr/local/bin/code 294 295 # systemctl shim - tells people to use 'service' if systemd is not running 296 cat << 'EOF' > /usr/local/bin/systemctl 297 #!/bin/sh 298 set -e 299 if [ -d "/run/systemd/system" ]; then 300 exec /bin/systemctl "$@" 301 else 302 echo '\n"systemd" is not running in this container due to its overhead.\nUse the "service" command to start services instead. e.g.: \n\nservice --status-all' 303 fi 304 EOF 305 chmod +x /usr/local/bin/systemctl 306 307 # Codespaces bash and OMZ themes - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme 308 codespaces_bash="$(cat \ 309 <<'EOF' 310 311 # Codespaces bash prompt theme 312 __bash_prompt() { 313 local userpart='`export XIT=$? \ 314 && [ ! -z "${GITHUB_USER}" ] && echo -n "\[\033[0;32m\]@${GITHUB_USER} " || echo -n "\[\033[0;32m\]\u " \ 315 && [ "$XIT" -ne "0" ] && echo -n "\[\033[1;31m\]➜" || echo -n "\[\033[0m\]➜"`' 316 local gitbranch='`\ 317 if [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \ 318 export BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || git rev-parse --short HEAD 2>/dev/null); \ 319 if [ "${BRANCH}" != "" ]; then \ 320 echo -n "\[\033[0;36m\](\[\033[1;31m\]${BRANCH}" \ 321 && if git ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \ 322 echo -n " \[\033[1;33m\]✗"; \ 323 fi \ 324 && echo -n "\[\033[0;36m\]) "; \ 325 fi; \ 326 fi`' 327 local lightblue='\[\033[1;34m\]' 328 local removecolor='\[\033[0m\]' 329 PS1="${userpart} ${lightblue}\w ${gitbranch}${removecolor}\$ " 330 unset -f __bash_prompt 331 } 332 __bash_prompt 333 334 EOF 335 )" 336 337 codespaces_zsh="$(cat \ 338 <<'EOF' 339 # Codespaces zsh prompt theme 340 __zsh_prompt() { 341 local prompt_username 342 if [ ! -z "${GITHUB_USER}" ]; then 343 prompt_username="@${GITHUB_USER}" 344 else 345 prompt_username="%n" 346 fi 347 PROMPT="%{$fg[green]%}${prompt_username} %(?:%{$reset_color%}➜ :%{$fg_bold[red]%}➜ )" # User/exit code arrow 348 PROMPT+='%{$fg_bold[blue]%}%(5~|%-1~/…/%3~|%4~)%{$reset_color%} ' # cwd 349 PROMPT+='$([ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ] && git_prompt_info)' # Git status 350 PROMPT+='%{$fg[white]%}$ %{$reset_color%}' 351 unset -f __zsh_prompt 352 } 353 ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_bold[cyan]%}(%{$fg_bold[red]%}" 354 ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%} " 355 ZSH_THEME_GIT_PROMPT_DIRTY=" %{$fg_bold[yellow]%}✗%{$fg_bold[cyan]%})" 356 ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg_bold[cyan]%})" 357 __zsh_prompt 358 359 EOF 360 )" 361 362 # Add RC snippet and custom bash prompt 363 if [ "${RC_SNIPPET_ALREADY_ADDED}" != "true" ]; then 364 echo "${rc_snippet}" >> /etc/bash.bashrc 365 echo "${codespaces_bash}" >> "${user_rc_path}/.bashrc" 366 echo 'export PROMPT_DIRTRIM=4' >> "${user_rc_path}/.bashrc" 367 if [ "${USERNAME}" != "root" ]; then 368 echo "${codespaces_bash}" >> "/root/.bashrc" 369 echo 'export PROMPT_DIRTRIM=4' >> "/root/.bashrc" 370 fi 371 chown ${USERNAME}:${group_name} "${user_rc_path}/.bashrc" 372 RC_SNIPPET_ALREADY_ADDED="true" 373 fi 374 375 # Optionally install and configure zsh and Oh My Zsh! 376 if [ "${INSTALL_ZSH}" = "true" ]; then 377 if ! type zsh > /dev/null 2>&1; then 378 apt_get_update_if_needed 379 apt-get install -y zsh 380 fi 381 if [ "${ZSH_ALREADY_INSTALLED}" != "true" ]; then 382 echo "${rc_snippet}" >> /etc/zsh/zshrc 383 ZSH_ALREADY_INSTALLED="true" 384 fi 385 386 # Adapted, simplified inline Oh My Zsh! install steps that adds, defaults to a codespaces theme. 387 # See https://github.com/ohmyzsh/ohmyzsh/blob/master/tools/install.sh for official script. 388 oh_my_install_dir="${user_rc_path}/.oh-my-zsh" 389 if [ ! -d "${oh_my_install_dir}" ] && [ "${INSTALL_OH_MYS}" = "true" ]; then 390 template_path="${oh_my_install_dir}/templates/zshrc.zsh-template" 391 user_rc_file="${user_rc_path}/.zshrc" 392 umask g-w,o-w 393 mkdir -p ${oh_my_install_dir} 394 git clone --depth=1 \ 395 -c core.eol=lf \ 396 -c core.autocrlf=false \ 397 -c fsck.zeroPaddedFilemode=ignore \ 398 -c fetch.fsck.zeroPaddedFilemode=ignore \ 399 -c receive.fsck.zeroPaddedFilemode=ignore \ 400 "${GITHUB_PROXY}https://github.com/ohmyzsh/ohmyzsh" "${oh_my_install_dir}" 2>&1 401 echo -e "$(cat "${template_path}")\nDISABLE_AUTO_UPDATE=true\nDISABLE_UPDATE_PROMPT=true" > ${user_rc_file} 402 sed -i -e 's/ZSH_THEME=.*/ZSH_THEME="codespaces"/g' ${user_rc_file} 403 404 mkdir -p ${oh_my_install_dir}/custom/themes 405 echo "${codespaces_zsh}" > "${oh_my_install_dir}/custom/themes/codespaces.zsh-theme" 406 # Shrink git while still enabling updates 407 cd "${oh_my_install_dir}" 408 git repack -a -d -f --depth=1 --window=1 409 # Copy to non-root user if one is specified 410 if [ "${USERNAME}" != "root" ]; then 411 cp -rf "${user_rc_file}" "${oh_my_install_dir}" /root 412 chown -R ${USERNAME}:${group_name} "${user_rc_path}" 413 fi 414 fi 415 fi 416 417 # Persist image metadata info, script if meta.env found in same directory 418 meta_info_script="$(cat << 'EOF' 419 #!/bin/sh 420 . /usr/local/etc/vscode-dev-containers/meta.env 421 422 # Minimal output 423 if [ "$1" = "version" ] || [ "$1" = "image-version" ]; then 424 echo "${VERSION}" 425 exit 0 426 elif [ "$1" = "release" ]; then 427 echo "${GIT_REPOSITORY_RELEASE}" 428 exit 0 429 elif [ "$1" = "content" ] || [ "$1" = "content-url" ] || [ "$1" = "contents" ] || [ "$1" = "contents-url" ]; then 430 echo "${CONTENTS_URL}" 431 exit 0 432 fi 433 434 #Full output 435 echo 436 echo "Development container image information" 437 echo 438 if [ ! -z "${VERSION}" ]; then echo "- Image version: ${VERSION}"; fi 439 if [ ! -z "${DEFINITION_ID}" ]; then echo "- Definition ID: ${DEFINITION_ID}"; fi 440 if [ ! -z "${VARIANT}" ]; then echo "- Variant: ${VARIANT}"; fi 441 if [ ! -z "${GIT_REPOSITORY}" ]; then echo "- Source code repository: ${GIT_REPOSITORY}"; fi 442 if [ ! -z "${GIT_REPOSITORY_RELEASE}" ]; then echo "- Source code release/branch: ${GIT_REPOSITORY_RELEASE}"; fi 443 if [ ! -z "${BUILD_TIMESTAMP}" ]; then echo "- Timestamp: ${BUILD_TIMESTAMP}"; fi 444 if [ ! -z "${CONTENTS_URL}" ]; then echo && echo "More info: ${CONTENTS_URL}"; fi 445 echo 446 EOF 447 )" 448 if [ -f "${SCRIPT_DIR}/meta.env" ]; then 449 mkdir -p /usr/local/etc/vscode-dev-containers/ 450 cp -f "${SCRIPT_DIR}/meta.env" /usr/local/etc/vscode-dev-containers/meta.env 451 echo "${meta_info_script}" > /usr/local/bin/devcontainer-info 452 chmod +x /usr/local/bin/devcontainer-info 453 fi 454 455 # Write marker file 456 mkdir -p "$(dirname "${MARKER_FILE}")" 457 echo -e "\ 458 PACKAGES_ALREADY_INSTALLED=${PACKAGES_ALREADY_INSTALLED}\n\ 459 LOCALE_ALREADY_SET=${LOCALE_ALREADY_SET}\n\ 460 EXISTING_NON_ROOT_USER=${EXISTING_NON_ROOT_USER}\n\ 461 RC_SNIPPET_ALREADY_ADDED=${RC_SNIPPET_ALREADY_ADDED}\n\ 462 ZSH_ALREADY_INSTALLED=${ZSH_ALREADY_INSTALLED}" > "${MARKER_FILE}" 463 464 echo "Done!"