'Bash script not exiting with "exit" without subshells (I think)
I'm using stow to manage my dotfiles and I'm writing a script that can set up my pc and packages automatically. I have all my config files in a config folder and that's the stow folder. What I'm basically doing is get the names of all folders (packages) in that folder and stowing them to my home directory. I also have a function that simply tells me if there was an error and exits the script.
I'm running this script on Arch Linux, recently installed, on the tty (I haven't installed a window manager yet). And when it goes to stow bash, it fails because .bashrc already exists in home. It gives me the error message, but it doesn't exit and I can't find the reason. I don't think I'm running the error function on a subshell like I've seen from other people with this problem, unless there's something I'm missing here...
Here's the function:
error () {
echo "!! ${1} !!"
exit 1
}
And then later on I have something like this:
ls -1 config | while read line; do
stow -d config -t ~ -R "${line}" || error "Failed to stow ${line}."
done
Here's the whole code from the creation of the function to the stowing:
step () {
echo "> ${1}"
}
substep () {
echo "--> ${1}"
}
error () {
echo "!! ${1} !!"
exit 1
}
success () {
echo "** ${1} **"
}
commandexists () {
# Check if a command exists
command -v $1 &> /dev/null
if [[ $? -eq 0 ]]; then
return 0
else
return 1
fi
}
pkg-install () {
pkg="${1:?"Error: pkg parameter unset."}"
step "${msg_install}: ${pkg}"
substep "Installing ${pkg} from the Arch Linux Repositories."
sudo pacman -Sy --noconfirm --needed "$pkg"
if [[ $? -ne 0 ]]; then
substep "Installing ${pkg} from the Arch User Repositories."
yay -Sy --noconfirm --needed "$pkg" || error "${msg_fail_install}: ${pkg}"
fi
success "${msg_success_install}: ${pkg}"
}
# Stop installation if yay is not installed
commandexists yay || error "Yay is not installed! Please install yay and try again."
# stow
pkg-install stow
step "Stowing config files"
ls -1 config | while read line; do
substep "Stowing ${line}"
stow -d config -t ~ -R "${line}" || error "Failed to stow ${line}."
done
success "Successfully stowed all config files"
As you can see, before stowing it checks if yay is installed by checking if the command exists. If not, it gives me an error and exits. When I run this on my other pc that doesn't have yay installed, it works as expected. It tells me yay is not installed and stops there. But why does it ignore the exit command in the stow part when I run it on the pc that has yay installed?
Solution 1:[1]
In this particular case, you can keep your while loop in the parent shell, while moving the ls into a subshell:
while IFS= read -r line; do
stow -d config -t ~ -R "${line}" || error "Failed to stow ${line}."
done < <(ls -1 config)
(Using IFS= makes your code work correctly with names that begin or end with whitespace; using -r makes it work correctly for names that contain literal backslashes).
...but don't do that in practice; ls output is unsuited to programmatic use.
Instead, use a glob:
for path in config/*; do
[[ -e $path || -L $path ]] || continue # detect case where config/ was empty
file=${path%config/} # strip the config/ off the name
stow -d config -t ~ -R "$file" || error "Failed to stow $file"
done
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Charles Duffy |
