我想通过添加一行来就地编辑文件,但前提是该脚本尚不具备防弹功能。

通常,我会执行以下操作:

cat >> ~/.bashrc <<EOF
export PATH=~/.composer/vendor/bin:$PATH
EOF


也可以通过ansible(line + insertafter=EOF + regexp)来做到这一点,但这是另一回事了。做类似的事情:

ex +'$s@$@\rexport PATH=\~/.composer/vendor/bin:$PATH@' -cwq ~/.bashrc


,但是理想情况下如何检查行是否已经存在(因此什么也不做)而不重复同一行?
或者也许在Ex编辑器中有一些更简单的方法?

评论

您不能外包吗? grep -Fq'导出PATH =〜/ .composer / vendor / bin:$ PATH'〜/ .bashrc ||前...(或猫)?

我相信这可能类似于此方法,但相反(当字符串不存在时,请执行某些操作)。

例如〜/ .bashrc -c“ if search('export PATH = \〜\ /。composer \ / vendor \ / bin:\ $ PATH')> 0 | norm quit | endif | norm Aexport PATH =〜/ .composer /供应商/ bin:$ PATH“

请注意,export是命令,因此该行的其余部分是一个shell单词,而不是赋值。因此,与使用变量赋值(不使用导出)不同,您需要双引号,否则它将在空白处中断。另请参阅如何正确地将路径添加到PATH。

我找到了昨天我一直在寻找的实际链接(尽管以上链接也很好)。局部变量赋值是否需要引号?

#1 楼

如果您想要防弹,可能需要比上面复杂的选项更轻便的东西。我会坚持使用ex的POSIX功能,使其变得愚蠢简单:只要删除该行(不管它存在多少次),就将其添加到文件末尾,然后保存并退出:
ex -sc 'g/^export PATH=\~\/\.composer\/vendor\/bin:$PATH$/d
$a
export PATH=~/.composer/vendor/bin:$PATH
.
x' ~/.bashrc


我锚定了正则表达式以增强鲁棒性,尽管我认为偶然匹配此正则表达式几乎是不可能的。 (锚定的意思是使用^$,因此仅当正则表达式与整行匹配时才匹配。) 。


还有许多其他简单的方法可以做到这一点。例如,将行添加到文件的末尾,然后通过外部UNIX过滤器运行文件的最后两行+cmd

ex -sc '$a
export PATH=~/.composer/vendor/bin:$PATH
.
$-,$!uniq
x' input


这非常非常简洁明了,并且完全兼容POSIX。它使用-c的Escape功能进行外部文本过滤,并使用POSIX指定的shell实用程序uniq

最重要的是,ex设计用于就地文件编辑,是迄今为止最便携的以非交互方式完成此任务的方式。实际上,它甚至早于原始的uniq-名称ex代表“视觉编辑器”,而基于它的非视觉编辑器是vi。并将其简化为一行),请使用vi将命令发送到ex

printf %s\n '$a' 'export PATH=~/.composer/vendor/bin:$PATH' . '$-,$!uniq' x | ex input


评论


相关:vi.stackexchange.com/q/6269/4676

–通配符
19年7月17日在2:29

#2 楼

一个可能的解决方案是创建一个函数来执行此操作:首先,我们创建一个局部变量l:res,该变量将用于计算该行的出现次数。

我们使用global命令:每次匹配行时,l:res都会递增。文件,因此我们要感谢l:res到最后一行,并使用G创建新行,并在其中添加要添加的行。

注1我用来设置o值的方法是有点沉重,可以用@Alex在他的答案中建议的内容替换为以下内容:使用参数:

function! AddLine()

    let l:res = 0
    g/export PATH=\~\/.composer\/vendor\/bin:\$PATH/let l:res = l:res+1

    if (l:res == 0)
        normal G
        normal oexport PATH=~/.composer/vendor/bin:$PATH
    endif

endfunction



请注意l:res的技巧,在字符前面添加escape()可能会导致搜索问题。 >
请注意,我仍然需要在调用函数时自行转义\(我没有设法自动转义\):

let l:res = search('export PATH=\~\/.composer\/vendor\/bin:\$PATH')




#3 楼

尝试:

ex ~/.bashrc -c "if search('export PATH=\~\/.composer\/vendor\/bin:$PATH')>0 | norm quit | endif | norm Aexport PATH=~/.composer/vendor/bin:$PATH"


请注意,:append不能在if endif -block的Ex模式下工作(请参阅VimDoc),因此我必须将norm A...放在外面。

#4 楼

我通常使用:

perl -i -p0e '$_.="export PATH=~/bin:$PATH\n" unless m!~/bin:!' ~/.bashrc


#5 楼

为了简化并避免出现许多\,要添加的行将是export PATH=mybin:PATH

主要策略:用text + mybin-path替换“ non-mybin”文本(所有文件) -定义:

 vim  +'s#\v%^((.|\n)(mybin:)@!)*%$#&\rexport PATH=mybin:PATH#e' -cx bashrc


,或者具有更多的教学缩进:

s#                                    substitute
   \v                                  very magical to redude \

   %^                                  file begin
   ((.|\n)(mybin:)@!)*                 multi-line str without "mybin:"
                                         (any char not followed by "mybin")*
   %$                                  end of file
 #                                    by


如果有匹配项:



&具有bashrc的全文,并且

&不包含/mybin:/


so:

 #                                    by ...
   &                                   all file
   export PATH=mybin:PATH              and the new path
 #e                                   don't complain if patt not found

-cx                                   save and leave 


更新:最后,我们可以制作一个vim脚本:

$ cat bashrcfix

#!/usr/bin/vim -s
:e ~/fakebashrc
:s#\v%^((.|\n)(mybin:)@!)*%$#&\rexport PATH=mybin:PATH#e
:x


chmod 755并安装它。用法:bashrcfix


注意:在\v模式下,=表示可选

#6 楼

这些答案中的大多数似乎对复杂的旧shell命令来说很复杂: >
编辑:grep的退出代码很重要,在这种情况下,需要使用! grep反转该代码;在这种情况下,grep -v将不会退出。谢谢@joeytwiddle的提示。

评论


我认为grep -v不会为您提供所需的退出代码。但是! grep应该这样做。

– joeytwiddle
15年10月4日,11:39

如果是这种情况,那么您甚至不需要-v就可以了!

– Sukima
2015年10月4日13:37

究竟。您可以编辑答案以进行更正。

– joeytwiddle
2015年10月4日在20:23



1.您应该使用-F,以便grep不会将字符解释为正则表达式,并且2.使用-q而不是重定向至/ dev / null。请参阅我先前对问题的评论。

–muru
2015年10月6日22:06

好点。好奇-q和-F选项的可移植性如何?我认为> / dev / null在不同平台之间更为通用(sun vs hp vs Mac OS X vs Ubuntu vs FreeBSD vs…)

– Sukima
2015年10月7日在21:46