我编写了一个shell脚本来将我的dotfiles存储库同步到我的主目录。这在Cygwin(zsh)中运行良好,但我刚刚迁移到Linux(zsh on Xubuntu 12.10)并且它失败了。
该脚本在repo中列出了相关的dotfiles,然后在创建符号链接之前,它会存档任何冲突。归档程序如下:
for i in $dotFiles; do
toArchive=$toArchive $(ls -d $i)
done
当$dotfiles
中的任何项目不存在时,此操作失败; ls
返回No such file or directory
,脚本终止。
将stderr
重定向到/dev/null
会解决此问题吗?即:
for i in $dotFiles; do
toArchive=$toArchive $(ls -d $i 2>/dev/null)
done
...还是有更好的解决方案?
(我的脚本是here,为了完整起见。)
答案 0 :(得分:1)
我不明白为什么你的脚本在第一个错误(set -e
生效??作为Makefile规则的一部分运行?)中终止的原因,但忽略任何命令的非零状态都可以通过运行
cmd || :
(读取:命令或true )。确实
$(ls -d $i || :)
诀窍?
PS:我看了你的剧本。实际上,set -e
已生效。您可能希望将其完全删除,或者仅针对脚本的特定区域选择启用它(set +e
撤消set -e
的效果。
答案 1 :(得分:1)
与其他shell不同,Zsh在文件名模式与任何内容不匹配时不执行命令。这意味着空目录中的echo hello *
实际上不会在屏幕上打印hello *
。相反,zsh将打印出错误消息并且echo
将不会被执行。
您可以使用默认情况下处于活动状态NOMATCH
的一个时髦选项来打开和关闭它。请阅读zsh关于其工作原理的信息页面。 chapter 2 in the zsh FAQ也解释了这一点。
但是,如果我正确地解释了您的意图,那么您有一个可能存在或可能不存在的文件名列表,并且您只希望在备份中包含文件名(如果存在)。如果是这种情况,那么这里是使用数组和文件存在测试的更好的版本:
typeset -a files_to_backup
for file in $dotFiles ; do
if [[ -f $file ]] files_to_backup=($files_to_backup $file)
done
如果您想知道,这也会为if
使用zsh的短条件语法。
答案 2 :(得分:1)
shell脚本最糟糕的事情就是让它工作。第二个最糟糕的是维持(在六个月内计算出每条线/期权的作用)。考虑到这一点,我建议你只添加一个存在检查:
for i in $dotFiles; do
if [[ -e $i ]]; then
toArchive=$toArchive $(ls -d $i)
fi
done
答案 3 :(得分:0)
我已经将这里发布的建议单独提取并整理成一个完整的解决方案。我不知道是什么打破了我脚本中的逻辑,但如果我猜测,我会说它可能正在解析ls
的结果和/或使用间隔字符串,而不是一个zsh数组......无论如何,工作脚本如下:
#!/bin/zsh
# Break on first error and unset variables
set -e
set -u
# Gather dotfiles
repoDir=$(pwd)
cd $repoDir/public
publicDotfiles=(.*)
cd $repoDir/private
privateDotfiles=(.*)
# Determine clashes, to backup
typeset -a toBackup
for file in $publicDotfiles $privateDotfiles; do
dotFile=$HOME/$file
if [[ -e $dotFile ]] toBackup=($toBackup $dotFile)
done
if [[ "$toBackup" != "" ]]; then
backupFile=$HOME/dotfiles.$(date +%Y%m%d).tar.gz
tar czPf $backupFile $toBackup --remove-files
fi
# Create symlinks
for i in $publicDotfiles; do
ln -s $repoDir/public/$i $HOME/$i
done
for i in $privateDotfiles; do
ln -s $repoDir/private/$i $HOME/$i
done
当我参与其中时,我的表现稍微强一些:
.gnupg
等等.Git会忽略它的内容,因此它们永远不会被推出。