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?
CodePudding user response:
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