【问题标题】:Why cat command not working in script为什么 cat 命令在脚本中不起作用
【发布时间】:2018-07-09 16:27:21
【问题描述】:

我有以下脚本,但它有一个错误。我正在尝试将所有文​​件合并为一个大文件。从命令行 cat commant 工作正常,内容被打印到重定向文件。从脚本它有时可以工作,但其他时间不行。我不知道为什么它的行为异常。请帮忙。

#!/bin/bash

### For loop starts ###

for D in `find . -type d`
do

        combo=`find $D -maxdepth 1 -type f -name "combo.txt"`
        cat $combo >> bigcombo.tsv

done

这是bash -x app.sh的输出

++ find . -type d
+ for D in '`find . -type d`'
++ find . -maxdepth 1 -type f -name combo.txt
+ combo=
+ cat
^C

更新: 以下对我有用。路径有问题。我仍然不知道是什么问题,所以欢迎回答。

#!/bin/bash

### For loop starts ###
rm -rf bigcombo.tsv

for D in `find . -type d`
do

                psi=`find $D -maxdepth 1 -type f -name "*.psi_filtered"`
                # This will give us only the directory path from find result i.e. removing filename.
                directory=$(dirname "${psi}")
                cat $directory"/selectedcombo.txt" >> bigcombo.tsv


done

【问题讨论】:

  • cat 工作正常,考虑到$combo 的未引用扩展。主要问题是您的find 命令并不总是找到至少一个文件。您可能只想要find . -maxdepth 2 -type f -name "combo.txt" -exec cat {} + > bigcombo.tsv 之类的东西。
  • 另外,为什么要使用反引号和“新”形式的命令替换,即directory=$(dirname "${psi}")directory=$(...) 形式是首选形式,因此加入 90 年代并停止使用反引号进行命令替换 ;-) 即 psi=`find $D -maxdepth 1 -type f -name "*.psi_filtered"` 应该是 psi=$(find $D -maxdepth 1 -type f -name "*.psi_filtered") 。祝你好运。

标签: linux bash scripting cat


【解决方案1】:

明显的问题是您试图cat 一个不存在的文件。

次要问题与效率和正确性有关。最好避免运行两个嵌套循环,尽管在这里将动作分成两个步骤只是不雅;内部循环最多只会执行一次。将命令结果捕获到变量中是常见的初学者反模式;通常可以避免只使用一次的变量,并避免在 shell 的内存中乱扔垃圾(巧合的是,它解决了缺少引用的多个问题 - 包含文件或目录名称的变量基本上应该总是用双引号插入)。重定向最好在任何包含循环之外执行;

rm file
while something; do
    another thing >>file
done

将在循环运行时多次打开、查找文件末尾、写入和关闭文件,而

while something; do
    another thing
done >file

只执行一次打开、查找和关闭操作,避免在开始循环之前必须清除文件。尽管您的脚本可以重构为根本没有任何循环;

find ./*/ -type f -name "*.psi_filtered" -execdir cat selectedcombo.txt \;> bigcombo.tsv

根据您的问题,存在包含combo.txt 但不包含任何*.psi_filtered 文件的目录可能是错误的。也许你想locate and examine these directories.

【讨论】:

  • 稍后我会尝试您的答案。但首先这部分find ./*/ 不会使脚本成为静态的。我想保持动态。其次,它是如何工作的,因为传统程序员会将 find 的输出分配给一个数组,然后循环遍历数组并 cat 每个文件。然而,这里似乎 find 会获取所有文件,然后运行 ​​cat 虽然它工作正常。
  • 我不明白这条评论。我想你想搜索当前目录的子目录,但是如果你也想包含当前目录,显然恢复到find . 等等。这并没有使它或多或少“动态”,它只是运行参数略有不同。
  • “传统”程序员通常不会将静态内容放入仅使用一次的变量中,就像我在答案中解释的那样。通常,管道比不必要地将结果捕获到变量中更有效且更惯用。正确的“传统”shell 脚本根本没有数组变量(它们是 ksh/Bash 扩展)。
  • find 按顺序处理其谓词,直到其中一个为假或谓词用完。 -execdir 谓词切换到find 正在处理的目录并执行命令(并检查其退出状态以确定谓词是否成功)。命令cat selectedcombo.txt 将命名文件的内容复制到标准输出,shell 已将其重定向到find 启动之前的文件。
  • 如果您来自 asm 或 C 等低级语言,请尽量避免将您的问题分成不必要的小部分。一个好的 shell 编程指南是尽量减少外部进程的数量。如果您有使用支持向量运算的数学工具的经验,那么思维的转变与您必须学习如何尽可能利用向量化运算的方式大致相似。
猜你喜欢
  • 2012-04-21
  • 2014-02-18
  • 2021-02-22
  • 1970-01-01
  • 2016-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-11
相关资源
最近更新 更多