我在脚本中发现了一些不属于主脚本的内容。:>
排成一行。
你能向我解释一下这是什么意思吗?
:> file
while read A B C D E; do echo "$A;$B;$D;$E;$C" >> file; done < otherfile
答案1
bash 脚本中有一行 :>。这是什么意思?
:> file
这是一种简洁的说法:
- 如果
file
不存在则创建它,否则将其截断为0
字节。
这意味着您可以确定它file
存在并且是空的。
您也可以使用,> file
但:> file
便携性更强。
请参阅 Stack Overflow 问题GNU Bash Builtin 中的“:”(冒号)有什么用途?了解更多信息。
答案2
这看起来像是一种创建新文件的奇特方式。其中bash
:
有一个空命令:
$ type :
: is a shell builtin
$ help :
:: :
Null command.
No effect; the command does nothing.
Exit Status:
Always succeeds.
>
将输出重定向:
到文件。
答案3
:
是 的另一个名称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
。
将输出字段分隔符设置为;
意味着您可以将多个字段作为参数传递以进行打印。 Shellread
将整行的其余部分连同空格一起分配给最后一个变量,但无法告诉 awk 只拆分为 5 个。 如果这很重要,也许只需继续使用 bash 循环,因为它在 awk 中不方便。 Perl 使这变得容易,因为它split
可以接受最大字段参数,但启动速度比 awk 慢得多。
实际上,这并不难,只是一个难写的正则表达式。为了获取行的其余部分而不是$5
在 awk 中,循环遍历字段仍然会丢失其原始空格。我的第一个可行想法是使用gensub
on $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
如果我可以复制/粘贴文字并显示它在输出中出现,这将更令人印象深刻。在 bash 中使用 ^Q 输入一个。ctrl-Q 表示将下一个按键引用为文字字符,因为 bash 的 emacs 样式行编辑与实际 emacs 相同。
http://mywiki.wooledge.org/BashFAQ有一些关于脚本的有用内容,无论您在脚本中输入什么数据或文件名,都不会中断。