使用管道读取文件,运行脚本并写入同一文件

5
我需要编写一行脚本,获取文件并在每行的末尾打印出现“word”的单词数。我可以使用另一个脚本来实现任何我想要的功能。 我的问题是,在运行脚本后,我发送给脚本的文件为空。 以下是该一行脚本:
#!/bin/bash
cat $1 | ./words_num word | cat $1

单词数

#!/bin/bash
while read line; do
    temp=`echo $line | grep $1 | wc -l`
    if (($temp==1)); then
        word_cnt=`echo $line | wc -w`
        echo "$line $word_cnt" 
    else 
        echo "$line"
    fi  
done
例如,在文件之前:
bla bla blaa word
words blaa
bla bla

文件后:

bla bla blaa word 4
words blaa 2
bla bla

Can you help?


  1. 存储到另一个文件中 2. 删除旧文件 3. 将新文件名重命名为旧文件名。或者您可以将整个文件读入变量中并迭代它,然后保存到同一文件中。
- Md. Minhazul Haque
你说“句子”,但你似乎注释的是“行”,而不是“句子”(也就是,以句号、问号或感叹号结尾的单词序列 —— 其中引号和括号等会有复杂性)。你真的是指“每行中出现单词‘word’的单词数”吗? - Jonathan Leffler
2个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
5
一句话概括:
cat $1 | ./words_num word | cat $1

is peculiar. 它大致等同于:

cat $1 | ./words_num word >/dev/null; cat $1

这段代码的预期结果可能不是你想要的。此外,它也有可能被评为“UUOC(使用cat命令无用)”奖项的候选者。

如果意图是用修改后的版本覆盖原始文件,则最好写成:

./words_num word < $1 > tmp.$$; mv tmp.$$ $1

如果您想在屏幕上看到结果,那么:

./words_num word < $1 | tee tmp.$$; mv tmp.$$ $1

如果中断了,两者都会留下临时文件。您可以通过以下方式避免此问题:

#!/bin/bash
trap "rm -f tmp.$$; exit 1" 0 1 2 3 13 15
./words_num word < $1 | tee tmp.$$
mv tmp.$$ $1
trap 0
陷阱设置信号处理程序(EXIT,HUP,INT,QUIT,PIPE,TERM),如果存在临时文件,则删除它并以失败状态退出。最后的trap 0取消了退出陷阱,因此命令成功退出。 至于words_num脚本,似乎需要调用awk而不是shell:
#!/bin/bash
[ $# == 0 ] && { echo "Usage: $0 word [file ...]" >&2; exit 1; }
word=$1
shift
awk "/$word/"' { print $0, NF; next } { print }' "$@"
如果你追求代码高效,可以缩短awk脚本的长度,但我更倾向于清晰易懂的代码。该脚本查找包含指定单词的行,打印该行以及该行字段数,并移至下一行。如果该行不匹配,则简单地打印。变量分配和移位意味着"$@"包含words_num的其他所有参数,awk会自动循环命名文件,或者在没有指定文件时读取标准输入。 该脚本应检查给定单词是否不含任何斜杠,因为这会破坏正则表达式(可以将其中每个出现的斜杠替换为[/],一个只包含斜杠的字符类)。完成这种程度的防护留给有兴趣的用户。

3
cat $1 | ./words_num word | tee $1

4
在小文件(几千字节内)上,这通常运行良好——如果你幸运的话。具体能处理多大取决于你所用操作系统管道缓冲区的大小,这可能是从大约4 KiB(符合POSIX最小要求)到64 KiB不等,但通常是5 KiB(基于历史惯例)。此外,还要依赖shell在启动tee之前启动cat,以及调度程序是否对你有利。如果你处理的文件大小为兆字节级别,这种方法将失败。 - Jonathan Leffler
@JonathanLeffler,有没有大文件的解决方案?! - ovgolovin
@JonathanLeffler 哦,我明白了。那么我们是否需要 tee(例如 <$1 >tmp.$$)呢?另外,为什么您不将其编写为单独的答案呢?我认为这是一个更通用的解决方案,而那个带有 tee 的解决方案只适用于小文件。 - ovgolovin
我们不确定是否需要 tee。在答案中,它将文件的新内容复制到标准输出(以及文件中)。我在我的评论中保持了同样的想法。看着这个带有 'cat $1 | ./words_num word | cat $1' 结构的问题,那么代码真的很奇怪。所显示的内容不应该破坏文件。(单词计数脚本呼吁使用 awk、Perl 或 Python 等进行重写)。 - Jonathan Leffler
@ovgolovin:我已经按照你的建议做了,提供了更详细的答案。我认为这涵盖了我们讨论的大部分内容。 - Jonathan Leffler
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,