ZSH/Shell变量赋值和使用

32

我在终端中使用 ZSH 作为我的 shell,虽然我已经编写了一些函数来自动化特定任务,但我从未尝试过需要当前所需功能的任何操作。

最近我使用 Jekyll 重新编写了博客,并希望使用类似于 scp 的东西自动化生成博客文章并将新生成的文件上传到我的服务器上。

我对 ZSH 中的变量绑定/使用有些困惑;例如:

DATE= date +'20%y-%m-%d'
echo $DATE

正确地输出了2011年8月23日,正如我所期望的那样。

但是当我尝试:

DATE= date +'20%y-%m-%d'
FILE= "~/path/to/_posts/$DATE-$1.markdown"
echo $FILE

它输出:

2011-08-23
blog.sh: line 4: ~/path/to/_posts/-.markdown: No such file or directory

当我想要运行博客标题(忽略字符串需要进行处理以使其更具URL友好性,并且路由路径path/to不存在)时,输出如下:

即,博客标题为"blog title",输出:

2011-08-23
blog.sh: line 4: ~/path/to/_posts/-blog title.markdown: No such file or directory

为什么$DATE在调用打印$FILE之前被打印,而不是字符串被包含在$FILE中?


date +%Y-%m-%ddate +20%y-%m-%d 更加简洁。date +%F 更加简洁明了。(这假设你的 date 命令支持这些格式;GNU date 支持,但其他可能不支持。) - Keith Thompson
2个回答

54

这里存在两个问题。


首先,你的第一个代码片段并没有达到你想要的效果。尝试移除第二行——echo语句。它仍然输出了日期,对吧?因为这里:

DATE= date +'20%y-%m-%d'

这不是一个变量赋值,而是一个调用带有辅助环境变量的date命令(一般语法为VAR_NAME=VAR_VALUE COMMAND)。你指的是这个:

DATE=$(date +'20%y-%m-%d')

你的第二个片段仍然会失败,但是失败的方式不同。你在使用invoke-with-environment语法而不是赋值。你应该这样写:

# note the lack of a space after the equals sign
FILE="~/path/to/_posts/$DATE-$1.markdown"

我认为那应该可以解决问题。


声明

虽然我非常了解bash,但我最近才开始使用zsh;可能有一些我不知道的zsh特性在起作用。


非常感谢,它完全按照我想要的方式工作。你是在哪里学习bash的,特别是像invoke-with-environment这样的东西?我可能会遇到更多问题,有一个可以参考的地方会很有帮助。 - HaaR
6
孩子,我的shell脚本是在街头学来的。说的是比喻,但确实如此。自1998年起,我每天都在使用Unix命令行,偶尔进行一些脚本编写,并且作为工作的一部分进行了一些严肃的脚本编写。我与其他懂得脚本编写的人一起工作并向他们学习。我在新闻组上提问。我阅读我使用的软件包中的脚本。当我找到好的文档时,我会仔细阅读——可惜的是,对于shell脚本来说,好的文档并不经常出现。 - Tom Anderson
6
有三份文档非常值得一读,它们是《高级Bash脚本指南》(Advanced Bash-Scripting Guide),虽然有些零散但却不可或缺,另外还有相当不错但可能让人望而生畏的《Bash参考手册》(Bash Reference Manual)和当然少不了man bash。你也应该阅读Richard KettlewellDavid Pashley所提供的优秀建议。 - Tom Anderson
在原始代码中,DATE= (带空格)的开头有什么作用?那整行代码和date +...之后的部分有什么区别? - Keshav
1
@Keshav 开始的 DATE= 后面跟着一个空格,会在定义了环境变量 DATE 为空字符串的环境中运行以下 date 命令。如果你写成 DATE=potato date +'20%y-%m-%d',它就会这样做,但是 DATE 被定义为 "potato"。空字符串只是最简单的情况!env 命令打印出环境变量,所以尝试比较 envDATE= envDATE=potato env 的输出。 - Tom Anderson

21

了解shell所谓的“扩展”的概念,有几种类型的扩展按特定顺序执行:

单词扩展的顺序如下:

  1. 波浪号扩展
  2. 参数扩展
  3. 命令替换
  4. 算术扩展
  5. 路径名扩展(如果没有设置set -f
  6. 引号移除,始终在最后执行

请注意,只有当波浪号未被引用时才执行波浪号扩展,例如:

$ FILE="~/.zshrc"
$ echo $FILE
~/.zshrc
$ FILE=~./zshrc
$ echo $FILE
/home/user42/.zshrc

变量赋值时,=周围不能有空格。

如果你想学习shell编程,以下是几个选择:

  • 阅读Shell的手册页 man zsh
  • 阅读POSIX shell规范,http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html,特别是当你想在不同操作系统上运行脚本时(而且你一定会遇到这种情况的!)
  • 阅读有关shell编程的书籍。
  • 加入usenet新闻组comp.unix.shell,在那里许多shell专家会回答问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接