微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Bash one-liner 将文本标记插入到第四个以及填充了文本的字段的所有连续选项卡中

如何解决Bash one-liner 将文本标记插入到第四个以及填充了文本的字段的所有连续选项卡中

这是一个适用于 Mac 的 Bash/.bat 终端脚本。

我正在尝试将文本 ("!!XX!!") 添加文件夹中的一组制表符分隔的 .txt 文件中,但我只想将其添加到该选项卡的第 4 个和所有后续事件中在每个 .txt 文件中,然后仅当这些 cel 中有文本时。因此,最终结果将类似于(假设信息的第 7 cel/field/bit 为空白)。所以转这个:

text01
text02
text03
text04
text05
text06

...进入这个:

text01 [TAB] text02 [TAB] text03 [TAB] text04!!XX!! [TAB] text05!!XX!! [TAB] text06!!XX!! [TAB]

文本标记“!!XX!!”以便不同系统中的另一个脚本可以在文件上运行并在“!!XX!!”的每个事件中执行特殊的系统兼容/自定义行格式,但我不想填充前三个字段/选项卡-分隔文本(因为那里不需要)或在空字段中(因为那里不需要)。

我已经用制表符替换了每一行返回,因此可以在那里进行,尽管我的偏好是稍后对带有行返回/格式的奇怪问题的制表符分隔文本 b/c 执行此操作来自 .rtf 文件。下面是我要替换每一行返回并用 TAB 替换它的内容(并且,是的,这是一个实际的行返回和其中的制表符,这似乎效果最好,因为... Macs?):

perl -pi -w -e 's/
/   /g' *.txt;

提前致谢:)

解决方法

这篇文章假设一个输入文件的行带有以制表符分隔的字段,其中从(并包括)第四个字段开始的每个字段如果有内容都需要编辑


一种方式

perl -F"\t" -wlane'
    for (3..$#F) { $F[$_] .= "!XX!" if defined $F[$_] }; print join("\t",@F)
' file

(在 tcsh shell 中需要用反斜杠转义那些 !。)一旦你测试了足够多的 -i 开关来改变输入 file 到位({ {1}} 保留备份)。

这使用 Perl 的 -i.bak 开关根据 -a 开关下给出的内容(或默认为空格)来中断输入行,结果数组位于 -F 中。见switches in perlrun

然后它从第四个字段迭代到最后一个。我使用语法 @F 作为数组 $#ary 的最后一个元素的索引。 我不知道“里面有文本”的单元格是多少,所以上面我测试了一个字段的 @ary-ness;因此,即使对于空字符串,这也会附加。适当调整。

或者使用正则表达式,这样可以提供更大的灵活性。例如,

defined

这会匹配所有字符,然后添加 for (3..$#F) { $F[$_] =~ s/.+\K/!XX!/ } (保留匹配的内容,通过 \K assertion)。使用正则表达式允许并要求更精确地指定那里接受的内容;显示的模式将匹配单独的空格,但不匹配空字符串。不触摸仅包含空格的字段,并删除尾随空格

!XX!

再次根据您的详细信息进行调整。

我不太明白关于换行符的讨论以及他们想要什么;上面的一行一行一行。如果这不是你需要的,请澄清。我没有要测试的 Mac,所以我无法评论所有这些。

一个用于准备测试和调整的独立示例

for (3..$#F) { $F[$_] =~ s/.+\S\K\s*/XX/ };

我将每个字段打印在单独的行上以便于检查。输入中的最后一个制表符后面只跟有尾随空格——这会导致一个空字段,但没有添加文本标记(如评论中所要求的那样)。

,

使用 GNU sed

$ echo text{01..07}$'\t' | sed -E 's/([^\t]+)(\t|$)/\1!!xx!!/4g'

text01   text02  text03  text04!!xx!! text05!!xx!! text06!!xx!! text07!!xx!!

 $ echo text{01..07}$'\t' | sed -E 's/\t([^\t]+)/\1!!xx!!/3g'
,

这是一个awk:

echo text{01..10}$'\t' | 
awk -v OFS=$'\t' '{for(i=1;i<=NF;i++) printf "%s%s",$i,i>=4 ? "XXX\t" : i<NF ? OFS : ORS }'

使用 perl,我会这样做:

echo text{01..10}$'\t' | 
perl -lpE '$cnt=0; s/\h+/++$cnt>=4 ? "XXX\t" : "\t"/ge;'

两者都打印:

text01  text02  text03  text04XXX   text05XXX   text06XXX   text07XXX   text08XXX   text09XXX   text10XXX   
,

假设每个文本文件包含 7 行,你可以这样做

paste -s *.txt | awk '
    BEGIN {FS=OFS="\t"}
    {for (i=4; i<=NF; i++) if ($i != "") $i = $i "!!XX!!"; print}
'

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。