我有一个平面文件,其中包含表示表中字段的数据列。我从外部源获取该文件,并希望将数据插入到数据库的表中。不幸的是,我收到的文件在特定列中缺少一个字段(添加的新字段)。由于我无法控制发送给我的内容,因此我想编辑文件并仅添加字段。可以sed
用于在每一行的特定列中添加文本吗?
例如,假设我有这个文件:
Alan Bradford 555-2012
Cathy Davies 555-7823
Edward Farris 555-9162
Gary Hobbs 555-5151
Irene Jacobs 555-1285
该文件缺少区号,所以我想213
在前面添加。我知道电话号码总是从第 31 列(纯字符数)开始。所以我希望它显示
Alan Bradford 213 555-2012
Cathy Davies 213 555-7823
Edward Farris 213 555-9162
Gary Hobbs 213 555-5151
Irene Jacobs 213 555-1285
我知道我可以通过三遍来完成此操作。我可以使用cut -c1-30
并获取第 1 部分,并cut -c31-
获取第 2 部分。然后我可以将它们全部粘贴在一起echo "$Part1 $NEWDATA $Part2" >> filename
我只是想知道是否有更简单的方法使用 sed 。我应该能够使用类似的东西
sed -e "30l,i213 " InFile > OutFile
我似乎无法正确理解在行上移动超过 30 个字符,然后插入 的语法213
。
有人知道什么可能有效,或者比我的剪切和粘贴选项更好吗?
更新
我被告知我的示例不够准确,我应该编辑问题以停止浪费人们的时间。我给出的例子对于这个问题来说非常准确:如何在位置 Y 中始终插入字符串“XXX”,无论它之前或之后是什么?
但没问题......这是我现实世界的例子。我有一个文本文件,每行包含 928 个字符。我想插入一个从位置 878 开始的字符串。字符串前后的值不能每次都相同,因为我要插入的位置后面的下一个字段是备注字段,通常但并非总是如此空白的。
@DonHolgo 的答案最有希望,也是一个很好的答案。但在我的 UNIX (AIX 7.1) 风格中,它似乎只允许您在出现错误之前跟踪最多 255 个字符。
这里我在第 255 列插入“XXX”:
# sed 's/.\{255\}/&XXX /' OrigTextFile
1 030680001001YNPO 14 H502 000595000000000000 1 0000680M00000100000004799000000000000479900000004799000000004799000000000000479900000 SDI42028820 20P561292 00000000000XXX 000000000000000000000000000000000000000000000000000000000000000 T 0000655000000000Y 0000516000000000E 0000280000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 20200814
但我尝试在第 256 列或更高列插入相同的操作:
# sed 's/.\{256\}/&XXX /' OrigTextFile
sed: 0602-404 Function s/.\{256\}/&XXX / cannot be parsed.
看起来我的 sed 版本有限制。所以我可能不得不执行我最初的剪切文本文件的计划。 File1 = 文本文件中每行的前 878 个字符 File2 = 我要添加的新字符串,原始文件中每行一行 File3 = 原始文本文件中的剩余字符。
然后加入他们:
# paste File1 File2 File3 > NewTextFile
答案1
您可以使用
sed 's/.\{30\}/&213 /' InFile > OutFile
将前 30 个字符(“任意字符”乘以 30)替换为其自身(&
)加上“213”。
答案2
您可以使用计数 RE。例如,x{12}
将匹配 12 个x
字符,并且y{1,3}
将匹配 1、2 或 3 个y
字符。这里我们将使用.{30}
匹配 30 个字符的通配符(即 30 个任意字符)。结果\1
字符串中的 与模式匹配中括号内的引用相匹配
sed -r 's#^(.{30})#\1213 #' file
在您更新的问题中,您现在说插入之前有 878 个字符。因此只需将示例中的 30 修改为现实中的 878 并插入XXX
sed -r 's#^(.{878})#\1XXX#' file
相同的过程可以适用于任何固定宽度的修改。
您perl
也可以使用,它没有困扰某些实现的行长度限制sed
,
perl -pe 's#^(.{878})#$1XXX#' file
答案3
您也可以尝试使用awk
awk '{sub(/^.{30}/,"&213 ")}1' file
这将附加213
到由该行的前 30 个字符组成的模式,无论它们是什么。
语法如下:
- 该
sub()
函数用于替代首先当前行上出现指定的正则表达式(如果没有明确说明要操作的字符串,则为默认目标)。 - 正则表达式为
^.{30}
,意思是“任意字符 30 次”,但从行首开始(“锚点” 的意思^
)。 - 替换是“找到的模式( 的含义
&
),后跟213
和 一个空格。 213
该行的其余部分将保持不变,从而有效地在前 30 个字符之后插入。
此操作在任何行上执行({ ... }
无条件操作块)。 awk
然后将打印修改后的行(程序1
末尾的awk
)。
答案4
如果您遇到了该工具的外部限制,您可以使用另一种方法,将 877 数字分解为 3 个单元,即 255 和剩余的 112。
skip=877
cmax=255
mult=`expr "$skip" / "$cmax"`
rem=`expr "$skip" % "$cmax"`
lim=".\\{$cmax\\}"
re="\\($lim\\)\\{$mult\\}.\\{$rem\\}"
sed -e "s/$re/&XXX/" your_file_nam
一种更简单的方法是使用Perl
:
perl -lpe 'substr($_, 877) =~ s/^/XXX/' your_file_name
Python:
python3 -c '
import sys
f, p, r = sys.argv[1:]
p = int(p)
with open(f) as fh:
print(*[l[:p]+r+l[p:] for l in fh],sep="",end="")
' file_name 877 "XXX"