xargs命令适用于ubuntu,但不适用于mac


4

我有以下代码行,用于将我的项目中的个人日期变量更新为今天的当前日期。这条线在Ubuntu的终端上工作,但Mac终端似乎远远落后。不幸的是,我从某个网站复制了这个片段,所以我不确定它是如何工作的。建议?

grep -ilr --exclude=revar.sh --exclude=README.md "[DATE]" * |
    grep -v .git | xargs -i@ sed -i "s/\[DATE\]/${today}/g" @

@Migrators:这是一个编程问题,使用shell脚本作为语言(以及更新源代码文件的目的)。它可能适合 SO和SU,但是因为它被问到了SO,为什么要迁移呢?

Answers:


4

它是如何工作的

  1. 生成文件名列表:

    grep -ilr --exclude=revar.sh --exclude=README.md "[DATE]" *
    

    以递归方式(-r)搜索文件,并列出(-l)文件内容不区分大小写的那些名称(-i)正则表达式“[DATE]”(这意味着该文件包含任何一个8个字符“AaDdEeTt”);排除名称revar.sh和README.md,和

  2. 从列表中删除包含字符后跟'git'的所有文件名(因此将删除文件名'agitator'):

    grep -v .git
    
  3. 一次处理一个文件,将特定的“sed”脚本应用于该文件。在现代符号中(POSIX - 和MacOS X,以及Linux,AIX,HP-UX,Solaris等):

    xargs -I@ sed -i "s/\[DATE\]/${today}/g" @
    

    'sed'的'-i'选项意味着在处理后覆盖输入文件。这是在POSIX标准中未指定的'sed'的GNU和BSD扩展。

什么是令人难以置信的

这个剧本可以在很多层面受到批评。

  • 第一个搜索字符串不正确;它应该在括号前有反斜杠;大多数文件至少包含一个字母'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所指出的那样,在这种情况下,没有必要使用'-i'或'-I'选项来'xargs'。

即使修复它也有用吗?

这让我感到疑惑它是如何有用的。在第一天,所有出现的'[DATE]'都映射到'2010-04-17';第二天会发生什么?在提交到git存储库之前,如何取消映射日期?

不过,至少你现在知道它的作用以及它是如何做到的。


我假设某种报道。有时探测太深也不值得......

1
就像@Donal说的那样,你真的不想知道为什么我需要这个。你的第二个例子实际上就是我所寻找的,感谢你的全面解释。但好奇的是,它没有将stdin传递给sed命令,它只是在sed命令中传递文件名。任何的想法? (我对Mac术语btw感到非常失望)。这是参考错误:'sed:1:“changelog”:命令c期望\后跟文本'
Corey hart

@Corey:'$ {today}'有点像'17 / 04/2010'吗?如果是这样,您需要将's ///'符号更改为's %%%' - 使用%或其他任何模式中未出现的字符来分隔替换操作的各个部分。我不确定你怎么会'认为'在混合中有一个改变命令。你是对的; xargs修复了一些事情,以便执行的命令为其输入提供/ dev / null,并将文件名作为参数进行操作。通过从tcsh切换到理智的shell来解决Mac术语有什么问题?你更喜欢哪种系统?
Jonathan Leffler

6

BSD xargs 不具有 -i,无论如何,这个选项在GNU xargs中被弃用了(这个指南是什么时候写的?1995年?)。使用 -I 代替。


谢谢,我只能在一天内学到很多东西,所以我非常依赖于我在互联网上阅读的东西。堕落是我猜的旧文章。
Corey hart

是的,在mac应该使用 -I,例如 redis-cli keys 'foo*' | xargs -I@ echo @
zhuguowei

3

-i 选项 xargs 当执行替换的地方在字符串的末尾时,永远不需要;无论如何,这就是放置文件名的地方。和BSD xargs (这是OSX提供的)也不支持该选项。试试这个:

grep -ilr --exclude=revar.sh --exclude=README.md "[DATE]" * |
    grep -v .git | xargs sed -i "s/\[DATE\]/${today}/g"

1

至于要在Mac OS X上进行sed的-i标志以便就地编辑文件,你必须添加一个空字符串作为参数:

sed -i "" 's/regex/replace/g' file

sed -i "" 's/regex/'"${var}"'/g' file   # create sed expression using string concatenation

或者用于创建备份文件名称的扩展名。 sed -i ".BAK" 's/regex/replace/g' file 将创建一个名为“file.BAK”的备份文件。
Dennis Williamson

0

使用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'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.