#!/usr/bin/env bash setDelimiters() { delimiters=("$@") } formatOptions() { options=() while read -r item; do options+=("${item}" "${delimiters[@]}") done < "$1" } # TODO: Add support for MBR boot mode checkUefi() { ls /sys/firmware/efi/efivars > /dev/null 2>&1 [ $? -ge 1 ] && printAndExit "This scripts supports only UEFI boot mode." } updateSystemClock() { timedatectl set-ntp true } printAndExit() { str="${1} Therefore, the installation process will stop, but you can continue where you left off by running:\n\nsh calsais" calcAndRun dialog --msgbox "\"\n${str}\"" HEIGHT 59 exit 1 } exitIfCancel() { [ $? -eq 1 ] && printAndExit "$@" } printWaitBox() { dialog --infobox "\nPlease wait..." 5 18 } partDisks() { dialog --yesno "\nDo you want me to automatically partition and format a disk for you?" 8 59 whipStatus=$? local IFS=$'\n' setDelimiters "" formatOptions <(lsblk -dpnlo NAME,SIZE -e 7,11) disks=$(lsblk -dpnl -e 7,11 | wc -l) result=$(dialog --menu "\nSelect the disk." 0 30 "$disks" "${options[@]}" 3>&1 1>&2 2>&3) exitIfCancel "You must select a disk." disk=$(echo "$result" | cut -d' ' -f1) if [ $whipStatus -eq 1 ]; then autoSelection=false msg="\nYou will partition the disk yourself and then, when finished, you will continue with the installation." dialog --msgbox "$msg" 8 56 partPrograms=("fdisk" "" "sfdisk" "" "cfdisk" "" "gdisk" "" "cgdisk" "" "sgdisk" "") partTool=$(dialog --menu "\nSelect the partitioning tool." 14 35 6 "${partPrograms[@]}" 3>&1 1>&2 2>&3) exitIfCancel "You must select a partitioning tool." $partTool "$disk" parts=$(lsblk "$disk" -pnl | sed -n '2~1p' | wc -l) [ "$parts" -lt 2 ] && printAndExit "You must at least create boot and root partitions." # TODO: Ask if the user wants a home partition formatOptions <(lsblk "${disk}" -pnlo NAME,SIZE,MOUNTPOINTS | sed -n '2~1p') result=$(dialog --menu "\nSelect the boot partition." 0 30 "$parts" "${options[@]}" 3>&1 1>&2 2>&3) exitIfCancel "You must select the boot partition." bootPart=$(echo "$result" | cut -d' ' -f1) formatOptions <(lsblk "${disk}" -pnlo NAME,SIZE,MOUNTPOINTS | sed -n '2~1p' | awk '$0!~v' v="$bootPart") result=$(dialog --menu "\nSelect the root partition." 0 30 "$parts" "${options[@]}" 3>&1 1>&2 2>&3) exitIfCancel "You must select the root partition." rootPart=$(echo "$result" | cut -d' ' -f1) remainingParts=$(lsblk "$disk" -pnl | sed -n '2~1p' | awk '$0!~v' v="$bootPart|$rootPart" | wc -l) if [ "$remainingParts" -gt 0 ]; then dialog --yesno "\nDo you have a swap partition?" 7 34 if [ $? -eq 0 ]; then formatOptions <(lsblk "${disk}" -pnlo NAME,SIZE,MOUNTPOINTS | sed -n '2~1p' | awk '$0!~v' v="$bootPart|$rootPart") result=$(dialog --menu "\nSelect the swap partition." 0 30 "$parts" "${options[@]}" 3>&1 1>&2 2>&3) exitIfCancel "You must select the swap partition." swapPart=$(echo "$result" | cut -d' ' -f1) else dialog --yesno "\nDo you want to create a swapfile?" 7 37 if [ $? -eq 0 ]; then size=$(getSize "swapfile") swapfile=/mnt/swapfile fi fi else dialog --yesno "\nDo you want to create a swapfile?" 7 37 if [ $? -eq 0 ]; then size=$(getSize "swapfile") swapfile=/mnt/swapfile fi fi else autoSelection=true bootPart=${disk}1 rootPart=${disk}2 dialog --yesno "\nDo you want to create a swap space?" 7 39 if [ $? -eq 0 ]; then result=$(dialog --menu "\nSelect the swap space." 0 26 2 "Partition" "" "Swapfile" "" 3>&1 1>&2 2>&3) exitIfCancel "You must select a swap space." size=$(getSize "${result,,}") if [ "$result" = "Partition" ]; then swapPart=${disk}2 rootPart=${disk}3 else swapfile=/mnt/swapfile fi fi printWaitBox autoPart fi printWaitBox formatPart mountPart } getSize() { sizeStr=$(dialog --inputbox "\nEnter the size of the ${1} (in GB, for example 1.5GB)." 10 63 3>&1 1>&2 2>&3) exitIfCancel "You must enter a size." size=$(echo "$sizeStr" | grep -Eo '[-]?[0-9]+([.,]?[0-9]+)?' | head -n1 | sed 's/,/./g' | awk '{ print int($1 * 1024) }') while [ "$(echo "$size" | awk '{ print $1 <= 0 }')" -eq 1 ]; do msg="\nThe size must be a number and cannot be less than or equal to zero. Please enter a new size." sizeStr=$(dialog --inputbox "$msg" 11 63 3>&1 1>&2 2>&3) exitIfCancel "You must enter a size." size=$(echo "$sizeStr" | grep -Eo '[-]?[0-9]+([.,]?[0-9]+)?' | head -n1 | sed 's/,/./g' | awk '{ print int($1 * 1024) }') done echo "$size" } createSwapfile() { dd if=/dev/zero of=$swapfile bs=1M count="${size}" status=progress 2>&1 | debug chmod 600 $swapfile 2>&1 | debug mkswap $swapfile 2>&1 | debug swapon $swapfile 2>&1 | debug } autoPart() { parted -s "$disk" mklabel gpt 2>&1 | debug sgdisk "$disk" -n=1:0:+300M -t=1:ef00 2>&1 | debug if [ -n "$swapPart" ]; then sgdisk "$disk" -n=2:0:+"${size}"M -t=2:8200 2>&1 | debug sgdisk "$disk" -n=3:0:0 2>&1 | debug else sgdisk "$disk" -n=2:0:0 2>&1 | debug fi } # TODO: Let the user choose the file system (and add encryption support) formatPart() { mkfs.fat -F 32 "$bootPart" 2>&1 | debug [ -n "$swapPart" ] && mkswap "$swapPart" 2>&1 | debug mkfs.ext4 "$rootPart" 2>&1 | debug } mountPart() { mount "$rootPart" /mnt 2>&1 | debug if [ $autoSelection = false ]; then mountOptions=("/boot/efi" "" "/boot" "" "==OTHER==" "") result=$(dialog --menu "\nSelect where to mount the boot partition." 0 30 4 "${mountOptions[@]}" 3>&1 1>&2 2>&3) exitIfCancel "You must select a path." bootPath=$(echo "$result" | sed 's/^\///g') if [ "$result" = "OTHER" ]; then local IFS=' ' result=$(dialog --inputbox "\nEnter the absolute path." 10 35 3>&1 1>&2 2>&3) exitIfCancel "You must enter a path." bootPath=$(echo "$result" | sed 's/^\///g') mkdir -p "/mnt/$bootPath" while [[ ! -d "/mnt/$bootPath" ]]; do result=$(dialog --inputbox "\nPath isn't valid. Please try again." 10 40 3>&1 1>&2 2>&3) exitIfCancel "You must enter a path." bootPath=$(echo "$result" | sed 's/^\///g') mkdir -p "/mnt/$bootPath" done else mkdir -p "/mnt/$bootPath" fi mount "$bootPart" "/mnt/$bootPath" 2>&1 | debug else bootPath="boot/efi" mkdir -p /mnt/$bootPath mount "$bootPart" /mnt/$bootPath 2>&1 | debug fi printWaitBox [ -n "$swapPart" ] && swapon "$swapPart" 2>&1 | debug [ -n "$swapfile" ] && createSwapfile saveVar "bootPath" "/$bootPath" } debug() { if [ "$debugFlagToStdout" = true ]; then tee elif [ "$debugFlagToFile" = true ]; then tee -a calsais.log > /dev/null elif [ "$debugFlag" = true ]; then tee -a calsais.log else tee > /dev/null fi } installPackage() { calcAndRun dialog --infobox "\"\nInstalling '$1'.\"" 5 WIDTH case ${3} in A) if [ "$debugFlagToStdout" = true ] || [ "$debugFlag" = true ]; then script -qec "pacstrap /mnt --needed ${1}" /dev/null 2>&1 | debug else pacstrap /mnt --needed "${1}" 2>&1 | debug fi ;; B) flag="" if [ "$2" != "R" ]; then runInChroot "pacman -Q ${1}" 2>&1 | debug [ $? -eq 0 ] && return flag="--needed" fi if [ "$debugFlagToStdout" = true ] || [ "$debugFlag" = true ]; then runInChroot "script -qec \"pacman -S $flag --noconfirm ${1}\" /dev/null" 2>&1 | debug else runInChroot "pacman -S $flag --noconfirm ${1}" 2>&1 | debug fi ;; C) flag="" if [ "$2" != "R" ]; then runInChroot "sudo -u $username paru -Q ${1}" 2>&1 | debug [ $? -eq 0 ] && return flag="--needed" fi if [ "$debugFlagToStdout" = true ] || [ "$debugFlag" = true ]; then runInChroot "script -qec \"sudo -u $username paru -S $flag --noconfirm --skipreview ${1}\" /dev/null" 2>&1 | debug else runInChroot "sudo -u $username paru -S $flag --noconfirm --skipreview ${1}" 2>&1 | debug fi ;; ?) printAndExit "INSTALL must be A, B or C in packages.csv file." ;; esac exitIfCancel "Package installation failed." } checkForParu() { commOutput=$(runInChroot "command -v paru > /dev/null 2>&1 || echo 1") if [ "$commOutput" = "1" ]; then runInChroot "sed -i 's/# %wheel ALL=(ALL:ALL) NOPASSWD: ALL/%wheel ALL=(ALL:ALL) NOPASSWD: ALL/' /etc/sudoers" checkSudoers printWaitBox runInChroot "cd /tmp; sudo -u $username git clone https://aur.archlinux.org/paru-bin.git; cd paru-bin; sudo -u $username makepkg -si --noconfirm" 2>&1 | debug fi } getThePackages() { set -o pipefail if [ ! -f "packages.csv" ]; then printWaitBox curl -LO "https://git.slc.ar/slococo/calsais/raw/branch/master/packages.csv" 2>&1 | debug shasum="$(sha256sum packages.csv | cut -d' ' -f1)" if [ ! "$shasum" = "8df3fb4189235980e992a4921d3eacf837162e029366d44e564b03b6e13ee788" ]; then dialog --yesno "\nThe package checksum verification failed. Do you still want to continue?" 7 39 if [ $? -ne 0 ]; then printAndExit "The package checksum verification failed." fi fi fi if [ "${1}" = "N" ]; then dialog --msgbox "\nA menu will appear where you can deselect the packages you don't want to be installed." 8 59 local IFS=$'\n' setDelimiters "" "ON" formatOptions <(grep "N" packages.csv | sed -n '2~1p' | cut -d',' -f1) msg="\nIf you don't want to install any packages, press Cancel." packages=$(dialog --separate-output --checklist "$msg" 28 46 19 "${options[@]}" 3>&1 1>&2 2>&3) tempFile=$(mktemp) for package in $packages; do grep "^$package," packages.csv >> "$tempFile" done header=$(head -n1 packages.csv) packages=$(sort <(sed -n '2~1p' packages.csv) <(cat "$tempFile") | uniq -d) printf '%s\n%s' "$header" "$packages" > packages.csv fi local IFS=, while read -r NAME IMPORTANT INSTALLER; do if [ "$IMPORTANT" = "${1}" ]; then installPackage "$NAME" "$IMPORTANT" "$INSTALLER" "${2}" < /dev/null fi done < packages.csv set +o pipefail } installImportantPackages() { msg="\nWe will continue with the installation of some important packages in the background. Please press OK and wait." dialog --msgbox "$msg" 8 60 dialog --infobox "\nUpgrading archlinux-keyring." 5 32 pacman -Sy --noconfirm archlinux-keyring 2>&1 | debug getThePackages "Y" "installImportantPackages" runInChroot "systemctl enable NetworkManager; systemctl enable fstrim.timer" 2>&1 | debug } generateFstab() { printWaitBox genfstab -U /mnt >> /mnt/etc/fstab } setTimeZone() { dialog --msgbox "\nNow, we will set the timezone." 7 34 setDelimiters "" formatOptions <(find -H /usr/share/zoneinfo -maxdepth 1 -mindepth 1 -type d -printf '%f\n' | sort | awk '!/posix/ && !/right/') region=$(dialog --menu "Select a region." 0 26 15 "${options[@]}" 3>&1 1>&2 2>&3) exitIfCancel "You must select a region." formatOptions <(find -H "/usr/share/zoneinfo/${region}" -maxdepth 1 -mindepth 1 -type f -printf '%f\n' | sort) city=$(dialog --menu "Select a city." 0 26 15 "${options[@]}" 3>&1 1>&2 2>&3) exitIfCancel "You must select a city." runInChroot "ln -sf \"/usr/share/zoneinfo/${region}/${city}\" /etc/localtime" printWaitBox runInChroot "hwclock --systohc" } setLocale() { # TODO: Let the user choose a locale sed 's/#en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' -i /mnt/etc/locale.gen printWaitBox runInChroot "locale-gen" 2>&1 | debug echo "LANG=en_US.UTF-8" > /mnt/etc/locale.conf } networkConf() { hostname=$(dialog --inputbox "\nEnter the hostname." 10 28 3>&1 1>&2 2>&3) exitIfCancel "You must enter a hostname." echo "${hostname}" > /mnt/etc/hostname echo " 127.0.0.1 localhost ::1 localhost 127.0.1.1 ${hostname}.localdomain ${hostname}" >> /mnt/etc/hosts unset hostname } calcAndRun() { argc="$#"; local i=1 for item in "$@"; do [ $i -eq $((argc-2)) ] && str="$item" [ "$item" = "WIDTH" ] && { function="calcWidth"; dimName="width"; } [ "$item" = "HEIGHT" ] && { function="calcHeight"; dimName="height"; } ((i++)) done dim=$($function "$str") comm=$(sed "s/${dimName^^}/$dim/g" <(echo "$@")) if [[ $comm != *"3>&1 1>&2 2>&3" ]]; then comm="${comm} 3>&1 1>&2 2>&3" fi commOutput=$(eval "$comm") exitStatus=$? [ -n "$commOutput" ] && echo "$commOutput" return $exitStatus } calcWidth() { count=1; found=false; option=1 while IFS= read -r -N 1 c; do if [[ "$c" == $'\n' ]]; then [ $count -ge $option ] && option=$count found=true count=-1 fi ((count++)) done < <(echo -ne "$1") [ $option -ge "$count" ] && count=option echo $((count+4)) } calcHeight() { newlines=$(echo -ne "$1" | grep -c $'\n') height=$(echo "${#1}" "$newlines" | awk '{ x = (($1 - $2 + ($2 * 60)) / 60) printf "%d", (x == int(x)) ? x : int(x) + 1 }') echo $((4+height)) } askForPassword() { password=$(calcAndRun dialog --insecure --passwordbox "\"\nNow, enter the password for $1.\"" 10 WIDTH) exitIfCancel "You must enter a password." passwordRep=$(dialog --insecure --passwordbox "\nReenter password." 10 30 3>&1 1>&2 2>&3) exitIfCancel "You must enter a password." while ! [ "$password" = "$passwordRep" ]; do password=$(dialog --insecure --passwordbox "\nPasswords do not match! Please enter the password again." 10 60 3>&1 1>&2 2>&3) exitIfCancel "You must enter a password." passwordRep=$(dialog --insecure --passwordbox "\nReenter password." 10 30 3>&1 1>&2 2>&3) exitIfCancel "You must enter a password." done unset passwordRep } setRootPassword() { askForPassword "root" "setRootPassword" runInChroot "echo \"root:${password}\" | chpasswd" 2>&1 | debug unset password } updateMirrors() { msg="\nNow, we will update the mirror list by taking the most recently synchronized HTTPS mirrors sorted by download rate." dialog --msgbox "$msg" 9 59 dialog --yesno "\nWould you like to choose your closest countries to narrow the search?" 8 55 if [ $? -eq 0 ]; then printWaitBox systemctl stop reflector.service cp /etc/pacman.d/mirrorlist /etc/pacman.d/mirrorlist.backup curl -o /etc/pacman.d/mirrorlist.pacnew https://archlinux.org/mirrorlist/all/ 2>&1 | debug local IFS=$'\n' setDelimiters "" "OFF" formatOptions <(grep '^##' /etc/pacman.d/mirrorlist.pacnew | cut -d' ' -f2- | sed -n '5~1p') countries=$(dialog --checklist "\nSelect your closest countries." 25 38 19 "${options[@]}" 3>&1 1>&2 2>&3) [ -z "$countries" ] && printAndExit "You must select at least one country." countriesFmt=$(echo "$countries" | sed -r 's/" "/,/g') printWaitBox reflector --country "${countriesFmt//\"/}" --protocol https --sort rate --save /etc/pacman.d/mirrorlist 2>&1 | debug else checkForSystemdUnit "mirrors update" "reflector.service" "oneshot" fi } grubSetUp() { printWaitBox [ -z $bootPath ] && tryLoadVar "bootPath" runInChroot "grub-install --target=x86_64-efi --efi-directory=${bootPath} --bootloader-id=GRUB" runInChroot "grub-mkconfig -o /boot/grub/grub.cfg" 2>&1 | debug } saveVar() { [ ! -f "calsais.vars" ] && touch calsais.vars if ! grep -q "$1" calsais.vars; then echo "$1=$2" >> calsais.vars else sed -i "s|$1=.*|$1=$2|" calsais.vars fi } loadVar() { [ -f "calsais.vars" ] && var=$(grep "$1=" calsais.vars | cut -d= -f2) || var="" export "$1"="$var" } tryLoadVar() { loadVar "$1" if [ -z "${!1}" ]; then calcAndRun dialog --msgbox "\"\nCouldn't load '$1'. Try to run the script again.\"" 7 WIDTH rm -f calsais.vars exit 1 fi } userSetUp() { username=$(dialog --inputbox "Enter the new username." 10 30 3>&1 1>&2 2>&3) && saveVar "username" "$username" exitIfCancel "You must enter an username." askForPassword "${username}" "userSetUp" runInChroot "useradd -m ${username};echo \"${username}:${password}\" | chpasswd; usermod -aG wheel ${username}" runInChroot "sed -i 's/# %wheel ALL=(ALL:ALL) ALL/%wheel ALL=(ALL:ALL) ALL/' /etc/sudoers" checkSudoers unset password } runInChroot() { cat << EOF > /mnt/cocoScript ${1} EOF chmod 755 /mnt/cocoScript arch-chroot /mnt /cocoScript return $? } checkSudoers() { runInChroot "visudo -c" 2>&1 | debug if [ $? -ne 0 ]; then dialog --msgbox "\nSudoers check failed. Try to run the script again." 7 54 cp /etc/sudoers /mnt/etc/sudoers exit 1 fi } installOtherPackages() { msg="\nNow, we will install a few more packages (in the background). Press OK and wait (it may take some time)." dialog --msgbox "$msg" 8 59 [ -z "$username" ] && tryLoadVar "username" getThePackages "S" "installOtherPackages" checkForParu getThePackages "N" "installOtherPackages" getThePackages "R" "installOtherPackages" runInChroot "sed -i 's/^%wheel ALL=(ALL:ALL) NOPASSWD: ALL/# %wheel ALL=(ALL:ALL) NOPASSWD: ALL/' /etc/sudoers" checkSudoers } finishInstallation() { if [ "$cdotfisInstall" = true ]; then [ -z "$username" ] && tryLoadVar "username" cp calsais /mnt/usr/bin/calsais echo "sh /usr/bin/calsais && logout" >> "/mnt/home/$username/.bashrc" fi rm -f /mnt/cocoScript umount -R /mnt dialog --yesno "\nFinally, the PC needs to restart, would you like to restart now?" 8 47 if [ $? -eq 0 ]; then reboot else clear fi } getDotfiles() { lastFolder=$(pwd -P) cd "$HOME/Documents" || printAndExit "Couldn't cd into $HOME/Documents" git clone --recursive "https://git.slc.ar/slococo/cdotfis.git" 2>&1 | debug cd cdotfis || printAndExit "Couldn't cd into ./cdotfis" sh sadedot/scripts/bootstrap.sh -p cd "$lastFolder" || printAndExit "Couldn't cd into $lastFolder" sudo rm -f ~/.bashrc /usr/bin/calsais mkdir -p "$HOME/.cache/zsh" touch "$HOME/.cache/zsh/.histfile" chsh -s "$(which zsh)" } checkForSystemdUnit() { if [ "${3}" = "oneshot" ]; then [ "$(systemctl show -p ActiveState --value "${2}")" = "inactive" ] && return else systemctl is-active --quiet "${2}" && return fi trapBackup=$(trap) trap 'systemctl stop ${2}; forceExit=true' INT forceExit=false commOutput=$(command -v paru > /dev/null 2>&1 && echo 0) if [ "$commOutput" = "0" ]; then calcAndRun dialog --infobox "\"\nWaiting for the ${1} to finish. Please wait.\"" 5 WIDTH fi if [ "${3}" = "oneshot" ]; then while [ $forceExit = false ]; do result=$(systemctl show -p ActiveState --value "${2}") [ "$result" = "inactive" ] && break sleep 1 done else systemctl is-active --quiet "${2}" while [ $? -ne 0 ] && [ $forceExit = false ]; do sleep 1 systemctl is-active --quiet "${2}" done fi eval "$trapBackup" } printStepIfDebug() { if [ "$debugFlagToFile" = true ] || [ "$debugFlag" = true ]; then printf '\n%s\n%s\n%s\n' "============================================================" "$step" \ "============================================================" >> calsais.log fi } steps=( checkUefi updateSystemClock partDisks updateMirrors installImportantPackages generateFstab setTimeZone setLocale networkConf setRootPassword grubSetUp userSetUp installOtherPackages finishInstallation ) usage() { cat << EOF usage: ${0##*/} [command] -h Print this help message. -d Print log to STDOUT and calsais.log file. -f Print log to calsais.log file. -s Print log to STDOUT. -p Install cdotfis (personal dotfiles). EOF } printLogo() { tput bold tput setaf 2 cat << END ,, ,, \`7MM db MM ,p6"bo ,6"Yb. MM ,pP"Ybd ,6"Yb. \`7MM ,pP"Ybd 6M' OO 8) MM MM 8I \`" 8) MM MM 8I \`" 8M ,pm9MM MM \`YMMMa. ,pm9MM MM \`YMMMa. YM. , 8M MM MM L. I8 8M MM MM L. I8 YMbmd' \`Moo9^Yo JMML M9mmmP' \`Moo9^Yo JMML M9mmmP' ====================================================== END tput sgr0 printf '\n\n\n%s\n' "Please wait..." } runScript() { debugFlag=false; debugFlagToFile=false; debugFlagToStdout=false; cdotfisInstall=false while getopts ':hdfsp' flag; do case $flag in h) usage && exit 0 ;; d) debugFlag=true ;; f) debugFlagToFile=true ;; s) debugFlagToStdout=true ;; p) cdotfisInstall=true ;; ?) printf '%s: invalid option -''%s'\\n "${0##*/}" "$OPTARG" && exit 1 ;; esac done clear if [ -d "$HOME/Documents" ]; then dialog --title "calsais" --msgbox "\nNow, we will finish the installation. Press OK and wait." 7 60 getDotfiles dialog --title "calsais" --msgbox "\nAll done!" 7 15 exit 0 fi local i=0; found=false loadVar "lastStep" if [ -n "$lastStep" ]; then for item in "${steps[@]}"; do if [ "$item" = "$lastStep" ]; then found=true break fi ((i++)) done if [ $found = false ]; then i=0 fi fi if [ $i -gt 0 ]; then welcomeMsg="Welcome back to calsais!" else systemctl stop reflector.service checkForSystemdUnit "systemd units" "graphical.target" systemctl --no-block start reflector.service welcomeMsg="Welcome to calsais!" printLogo sed -i -e '/^\[extra\]/,/^Include/ s/^/#/' -e '/^\[community\]/,/^Include/ s/^/#/' /etc/pacman.conf pacman -Sy --needed --noconfirm dialog 2>&1 | debug sed -i -e '/\[extra\]/,/Include/ s/^#//' -e '/\[community\]/,/Include/ s/^#//' /etc/pacman.conf fi if [ ! -f "/etc/dialogrc" ]; then curl -LO "https://git.slc.ar/slococo/cdotfis/raw/branch/master/dotfiles/.dialogrc" 2>&1 | debug mv .dialogrc /etc/dialogrc fi tput reset trap 'printAndExit "Received SIGINT signal."' INT calcAndRun dialog --title "calsais" --msgbox "\"\n${welcomeMsg}\"" 7 WIDTH while [ $i -lt "${#steps[@]}" ]; do step=${steps[$i]} printStepIfDebug saveVar "lastStep" "$step" $step ((i++)) done } runScript "$@"