1

我编写了一个 shell 脚本来将我的 dotfiles 存储库同步到我的主目录。这在 Cygwin(zsh)中运行良好,但我刚刚迁移到 Linux(Xubuntu 12.10 上的 zsh)并且失败了。

该脚本在 repo 中列出了相关的点文件,然后在创建符号链接之前,它会存档任何冲突。归档程序如下:

for i in $dotFiles; do
  toArchive=$toArchive $(ls -d $i)
done

当其中的任何项目$dotfiles不存在时,这将失败;ls返回No such file or directory并且脚本终止。

会重定向stderr/dev/null解决这个问题吗?IE:

for i in $dotFiles; do
  toArchive=$toArchive $(ls -d $i 2>/dev/null)
done

...或者有更好的解决方案吗?

(为了完整起见,我的脚本在这里。)

4

4 回答 4

2

shell脚本最糟糕的事情是让它工作。第二个最糟糕的是维持(在六个月内无法弄清楚每条线/选项做了什么)。考虑到这一点,我建议您只添加一个存在检查:

for i in $dotFiles; do
  if [[ -e $i ]]; then
      toArchive=$toArchive $(ls -d $i)
  fi
done
于 2012-12-11T09:56:25.040 回答
1

我不明白为什么您的脚本在第一个错误时终止(set -e实际上?作为 Makefile 规则的一部分运行?),但是可以通过运行忽略任何命令的非零状态

 cmd || :

(阅读:command 或 true)。做

  $(ls -d $i || :)

做这个把戏?

PS:我看了你的剧本。事实上,set -e是有效的。您可能希望完全删除它或仅针对脚本的特定区域选择性地打开它(set +e撤消 的效果set -e)。

于 2012-12-10T10:38:43.073 回答
1

Zsh 与其他 shell 不同,当文件名模式不匹配任何内容时,它不会执行命令。这意味着echo hello *空目录中的 an 实际上不会hello *在屏幕上打印。相反,zsh 将打印所述错误消息并且echo不会被执行。

NOMATCH您可以使用默认激活的那些时髦选项之一来打开和关闭它。请阅读 zsh 的信息页面,了解它是如何工作的。zsh FAQ 中的第 2 章也对此进行了解释。

但是,如果我正确地解释了您的意图,那么您将拥有一个可能实际存在或可能不存在的文件名列表,并且您只想在备份中包含一个文件名(如果存在)。如果是这种情况,那么这里是使用数组和文件存在测试的更好版本:

typeset -a files_to_backup
for file in $dotFiles ; do
  if [[ -f $file ]] files_to_backup=($files_to_backup $file)
done

if如果您想知道的话,这也使用 zsh 的简短条件语法。

于 2012-12-11T08:14:32.273 回答
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 忽略,所以它们永远不会被推出。
  • 如果脚本是从它自己的目录运行的,那么项目文件夹可以在任何地方,然后脚本会计算出绝对路径。
于 2012-12-11T22:42:29.863 回答