我有以下代码行,用于将项目中的个人日期变量更新为今天的当前日期。此行在 Ubuntu 终端中有效,但 Mac 终端似乎远远落后。不幸的是,我从某个网站复制了此代码片段,因此我不确定它究竟是如何工作的。有什么建议吗?
grep -ilr --exclude=revar.sh --exclude=README.md "[DATE]" * |
grep -v .git | xargs -i@ sed -i "s/\[DATE\]/${today}/g" @
答案1
它是如何工作的
生成文件名列表:
grep -ilr --exclude=revar.sh --exclude=README.md "[DATE]" *
以递归方式 (-r) 搜索文件并列出 (-l) 文件内容与正则表达式 '[DATE]' 不区分大小写 (-i) 匹配的文件名称(表示文件包含 8 个字符“AaDdEeTt”中的任意一个);排除名称 revar.sh 和 README.md,并且
从列表中删除所有包含字符“git”的文件名(因此文件名“agitator”将被删除):
grep -v .git
一次处理一个文件,将特定的“sed”脚本应用于文件。在现代符号中(POSIX - 和 MacOS X,以及 Linux、AIX、HP-UX、Solaris 等):
xargs -I@ sed -i "s/\[DATE\]/${today}/g" @
“sed”的“-i”选项表示在处理后覆盖输入文件。这是 GNU 和 BSD 对“sed”的扩展,POSIX 标准中未指定。
难以置信的是什么
这个剧本可以在多个层面受到批评。
- 第一个搜索字符串不正确;它应该在括号前有反斜杠;大多数文件至少包含一个字母“dateDATE”。
- 第二个 grep 大概是要删除“.git”目录下的所有内容,需要修复。
- 与第一个“grep”不同,“sed”命令在查找“[DATE]”时不区分大小写。
如何修复
因此,两种选择之一都是有意义的。
任何一个:
grep -ilr --exclude=revar.sh --exclude=README.md "\[DATE\]" * |
grep -v '\.git/' |
xargs sed -i "s/\[[Dd][Aa][Tt][Ee]\]/${today}/g"
或者:
grep -lr --exclude=revar.sh --exclude=README.md "\[DATE\]" * |
grep -v '\.git/' |
xargs sed -i "s/\[DATE\]/${today}/g"
正如 Donal Fellows 所指出的,在这种情况下没有必要使用‘xargs’的‘-i’或‘-I’选项。
即使修好了还有用吗?
这让我很困惑它到底有什么用。第一天,所有出现的 '[DATE]' 都映射到 '2010-04-17';第二天会发生什么?如何在提交到 git 存储库之前取消日期映射?
不过,至少你现在知道它的作用是什么以及它是如何做到的。
答案2
BSDxargs
没有-i
,而且该选项在 GNU xargs 中已被弃用(本指南是什么时候写的?1995 年?)。请改用-I
。
答案3
当执行替换的位置在字符串末尾时,永远不需要-i
选项;文件名无论如何都会放在那里。而且 BSD (OSX 提供的)也不支持该选项。所以试试这个:xargs
xargs
grep -ilr --exclude=revar.sh --exclude=README.md "[DATE]" * |
grep -v .git | xargs sed -i "s/\[DATE\]/${today}/g"
答案4
使用 Bash 参数扩展您还可以几乎自动地避免 sed 格式问题:
# some basic Bash parameter expansion examples to play with
var='ddd/abc/ddd'
var="$(date)"
var=$'\\\n'
echo abc | sed 's/b/'"${var}"'/g'
echo abc | sed 's/b/'"${var//\//\\/}"'/g'