bash中这个奇怪的符号“:>”是什么意思


47

我在脚本中找到了一些东西,但不属于主脚本。有:>在一条线上。

你能告诉我这是什么意思吗?

:> file
while read A B C D E; do echo "$A;$B;$D;$E;$C" >> file; done < otherfile

6
重要的:>是,不是单个运算符。如果您改为阅读它,可能会更容易理解: > file
jpfx1342

这意味着编写脚本的人应该已经将循环的输出重定向到文件:while read A B C D E; do echo "$A;$B;$D;$E;$C"; done < otherfile > file。或者更好的是,他们应该使用正确的工具,如Peter所建议的 awk 。顺便说一句,您几乎总是希望将-r开关与配合使用read
汤姆·费内奇

在bash之外,这对于乌鸦来说是一个笑脸。
smci 2015年

Answers:


46

bash脚本的一行中有:>。这是什么意思?

:> file

这是一种简短的说法:

  • 如果file不存在,则创建它,否则将其截断为0字节。

这意味着您可以确定它file存在并且为空。

您也可以使用,> file:> file更便于携带。

请参阅堆栈溢出问题,“:”(冒号)内置GNU Bash的目的是什么?欲获得更多信息。


我不明白第二行。我以为,那读就是读变量。命令回显也很奇怪。你能解释一下吗?
diego9403's

我不是Unix专家,但我认为第二行从中读取内容otherfile并将echo其发送给file。它还会根据所读取的内容生成变量...如果您想确定的答案,请提出您自己的问题。
DavidPostill

2
@ diego9403:read从stdin获取输入。它会自行读取您键入的内容。由于已将stdin重定向到,<otherfile然后将其内容otherfile“键入”到stdin中。因此read,将值逐行放入变量$ A,$ B,$ C,$ D和$ E。
slebetman'9

因此,它只是truncatecoreutils的一个更晦涩的替代方案?
Federico Poloni

1
@PeterCordes我并不是说“晦涩难懂”,而不是“鲜见”,而是因为“读者不太清楚”。
Federico Poloni 2015年

29

看来是创建新文件的一种好方法。In bash :是一个空命令:

$ type : 
: is a shell builtin 
$ help : 
:: :
    Null command.

    No effect; the command does nothing.

    Exit Status:
    Always succeeds.

>将输出重定向:到文件。


2
如果文件已经存在,它也会截断...
DavidPostill

2
是的,这是什么>
的Arkadiusz Drabczyk

2
:是的简写true。可能在某些外壳中,true不是内置的吗?两者都是bash内置的。
彼得·科德斯

12

:是的另一个名称true。两者都是bash中的shell内置程序,但是没有/bin/:,只有一个/bin/true。输出重定向会导致Shell到open(2)文件O_CREAT|O_TRUNC。如果未写入任何内容,则它将保持零长度。

将这两部分放在一起,:> file是截断文件的相当普遍的习惯用法。不过,大多数人会尝试通过书写来使它看起来不那么怪异: >file


既然您在第二行的评论中提问,我将把我的评论变成答案。(即使您没有在问题中问这个。)

第二行是一个循环,将从中读取行otherfile到一些命名变量中。循环主体使用分隔符而不是之前的空白echo来打印它们;file在每次迭代中关闭并重新打开(用于追加),因为重定向位于循环内部。使用while ...;do read -r ...;done <otherfile >file会减少麻烦,并且避免首先截断文件。read -r\作为逃脱角色进食。

bash中的文本处理非常慢。其中一部分是不可避免的:read必须一次传送一个字节(read(2)每个字节一次系统调用),以免超出行尾。最好使用正确的工具来完成这项工作:

awk -vOFS=';' '{ print $1, $2, $4, $5, $3 }' -- otherfile  >file

--表示如果您的脚本otherfile被命名为愚蠢的像,它不会中断--version

将输出字段分隔符设置为;意味着您可以将多个字段作为args传递进行打印。Shell read将带有空格的整个行的其余部分分配给最后一个变量,但是没有办法告诉awk只拆分为5。如果这很重要,则也许继续使用bash循环,因为它在awk中很不方便。Perl使这个过程变得容易,因为它split可以使用max-fields arg,但是它的启动要比awk慢得多。

实际上,事实并非如此,只是编写一个难看的正则表达式。要获得其余内容而不是$5awk,遍历字段仍然会丢失其原始空格。我的第一个可行的想法是用gensub$0(整行)删除第4场(即非空间其次是空间),让一切:

awk -vOFS=';' '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1); print $1, $2, $4, tail, $3 }' -- otherfile >file

第一次尝试时我做对了,但是我对此印象深刻,这一事实说明了该awk代码的可读性。>。<

请注意,它与print以前一样,但是用tail代替$5

echo 'A  B c DD    e      f g    f' | 
  awk -vOFS=\; '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1);
   print $1, $2, $4, tail, $3 }'

A;B;DD;e       f g    f;c

如果我可以复制/粘贴文字并将其显示在输出中,这会给人留下深刻的印象。用^ Q在bash中键入一。ctrl-Q表示将下一个按键作为文字字符引用,因为bash的emacs样式的行编辑与此实际emacs相同。

http://mywiki.wooledge.org/BashFAQ提供了一些有用的脚本知识,无论您在脚本中抛出什么数据或文件名,它们都不会中断。

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.