【问题标题】:How to make and name multiple text files after using the cut command?使用cut命令后如何制作和命名多个文本文件?
【发布时间】:2019-08-16 18:54:58
【问题描述】:

我有大约 50 个数据文本文件需要从中删除几列。

我一直在使用cut 命令单独删除和重命名它们,但我将拥有更多文件并且需要一种方法来大规模执行此操作。

目前我一直在使用:

cut -f1,6,7,8 filename.txt >> filename_Fixed.txt

我可以使用以下方法从所有文件中删除列:

 cut -f1,6,7,8 *.txt 

但我只能在终端中获取所有输出,或者我可以将其写入单个文本文件。

我想要的是使用 cut 编辑几个文件以删除所需的列:

filename1.txt
filename2.txt
filename3.txt
filename4.txt
.
.

.

并将编辑后的输出写入单个文件:

filename_Fixed1.txt
filename_Fixed2.txt
filename_Fixed3.txt
filename_Fixed4.txt
.
.

.

但一直无法找到将输出写入新文本文件的方法。我是使用命令行的新手,而且编码人员不多,所以也许我不知道要搜索哪些术语?我什至无法在谷歌搜索中找到任何对我有帮助的东西。看起来应该很简单,但我很挣扎。

无奈之下,我确实尝试了这段代码,但知道它不起作用:

cut -f1,6,7,8 *.txt >> ( FILENAME ".fixed" ) 

我发现">>" 之后的部分嵌套在输出多个文件的awk 命令中。

我也尝试(再次知道它行不通)对输出文件进行通配符,但得到了一个模棱两可的重定向错误。

【问题讨论】:

    标签: bash shell text command-line filenames


    【解决方案1】:

    你试过for吗?

    for f in *.txt ; do
        cut -f 1,6,7,8 "$f" > $(basename "$f" .txt)_fixed.txt
    done
    

    (注意,我现在无法尝试basename,您可以将其替换为"${f}_fixed"

    【讨论】:

    • 我做到了!就像 3 天前一样......我完全忘记了,但这是一个 for 循环,其中包含一些令人尴尬且非常错误的代码,试图将输出放入不同的文件中。顺便说一句,这完全有效。非常感谢您花时间回答这么简单的问题!!!
    • @AlexisDodson 我的荣幸 :)
    【解决方案2】:

    您也可以在awk 本身中处理它,这将使处理过程更加高效,尤其是对于大量文件,例如:

    awk '
        NF < 8 { 
            print "contains less than 8 fields: ", FILENAME
            next
        }
        {   fn=FILENAME
            idx=match(fn, /[0-9]+.*$/)
            if (idx == 0) {
                print "no numeric suffix for file: ", fn
                next;
            }
            newfn=substr(fn,1,idx-1) "_Fixed" substr(fn,idx)
            print $1,$6,$7,$8 > newfn
        }
    ' *.txt
    

    其中包含两个规则({...} 之间的表达式)。第一个:

        NF < 8 { 
            print "contains less than 8 fields: ", FILENAME
            next
        }
    

    只需检查文件是否包含至少 8 个字段(因为您希望字段 8 作为最后一个字段)。如果文件包含的字段少于 8 个,它只会跳到列表中的 next 文件。

    第二条规则:

        {   fn=FILENAME
            idx=match(fn, /[0-9]+.*$/)
            if (idx == 0) {
                print "no numeric suffix for file: ", fn
                next;
            }
            newfn=substr(fn,1,idx-1) "_Fixed" substr(fn,idx)
            print $1,$6,$7,$8 > newfn
        }
    
    • fn=FILENAME 将当前文件名存储为 fn 以减少输入,
    • idx=match(fn, /[0-9]+.*$/) 定位文件名的数字后缀开始的索引(例如,"3.txt" 开始),
    • if (idx == 0) 则未找到数字后缀,警告并转到next 文件,
    • newfn=substr(fn,1,idx-1) "_Fixed" substr(fn,idx) 由非数字前缀(例如"filename")形成新文件名,添加 "_Fixed" 并连接字符串,然后添加数字后缀,最后
    • print $1,$6,$7,$8 &gt; newfn 打印字段(列)1,6,7,8 将输出重定向到新文件名。

    有关上面使用的每个字符串函数的详细信息,请参阅GNU awk User's Guide - 9.1.3 String-Manipulation Functions

    如果我理解您的尝试,这应该能够处理尽可能多的文件——只要文件有一个数字后缀,可以在文件名之前放置 "_Fixed" 并且每个文件至少有 8 个字段(列)。您可以在命令行中复制/鼠标中键粘贴整个命令进行测试。

    【讨论】:

    • 也许有点矫枉过正,但我​​喜欢它,+1 :)
    • 谢谢。是的,与cut 相比要长一些,但对于大量文件(这是awk 的亮点),它的运行速度会快几个数量级。 awk 在单个进程中运行。在带有命令替换的循环中使用 shell & cut 时,每次迭代都会产生 3 个子shell(1-cut、2-basename、3-command-substitution)。对于 500 个文件,即 1500 个子外壳,运行时间差异将是几秒,对于超过 1.5B 个子外壳的 5,000,000 个文件,运行时间差异将以小时为单位。
    • 产生的子shell是我们很容易忘记的东西。谢谢提醒。
    猜你喜欢
    • 2019-10-05
    • 2015-07-19
    • 1970-01-01
    • 2016-02-19
    • 2013-02-05
    • 2012-12-07
    • 1970-01-01
    • 2014-12-23
    • 1970-01-01
    相关资源
    最近更新 更多