我有一个如下文件
'ABC'|filler|'Y'|'john/1'|'text'
'ABC'|filler|'Y'|'john/1'|'te/xt'
'ABC'|filler|'N'|'mary/2'|'text'
'DEF'|filler|'N'|'jane/3'|'text'
在最初的 grep 之后,
$ wordY="'Y'|"
$ wordN="'N'|"
$ grep ABC test.txt | grep "$wordY\|$wordN'[[:alpha:]]+/"
正在返回
'ABC'|filler|'Y'|'john/1'|'text'
'ABC'|filler|'Y'|'john/1'|'te/xt'
'ABC'|filler|'N'|'mary/2'|'text'
我现在希望/
仅删除名称并将其保存到新的 .txt 文件
所以我的理想输出是
'ABC'|filler|'Y'|'john1'|'text'
'ABC'|filler|'Y'|'john1'|'te/xt' -- / should not be removed for 'te/xt'
'ABC'|filler|'N'|'mary2'|'text'
如何添加到命令中以获取输出?
答案1
假设输入是一个用作|
字段分隔符的“简单”CSV 文件,并且没有带有嵌入分隔符或换行符的字段,我们可以使用awk
它来寻址我们想要修改的特定字段。
$ awk -F '|' -v sq="'" 'BEGIN { OFS = FS } $1 == sq "ABC" sq { gsub("/","",$4); print } ' file
'ABC'|filler|'Y'|'john1'|'text'
'ABC'|filler|'Y'|'john1'|'te/xt'
'ABC'|filler|'N'|'mary2'|'text'
我们-F '|'
将awk
输入读取为|
分隔字段的换行符分隔记录。由于在内联awk
脚本中处理单引号可能很棘手并导致代码不可读,因此我们还将awk
变量设置sq
为单引号字符。
该代码检测第一个字段的值恰好为 的任何记录'ABC'
,并且对于这些记录,它会在输出(可能)修改的记录之前删除第四个字段中的所有斜杠。
我们还可以避免对任何第一个字段数据进行硬编码,而只需将我们想要检测的整个字符串传递到变量中(此处为query
):
$ awk -F '|' -v query="'ABC'" 'BEGIN { OFS = FS } $1 == query { gsub("/","",$4); print } ' file
'ABC'|filler|'Y'|'john1'|'text'
'ABC'|filler|'Y'|'john1'|'te/xt'
'ABC'|filler|'N'|'mary2'|'text'
正如下面的评论所指出的(现已删除),您可以可能仅当修改后的记录在第四列中实际包含斜杠时才输出。这可能简化我们的命令有点:
awk -F '|' -v query="'ABC'" 'BEGIN { OFS = FS } $1 == query && gsub("/","",$4)' file
该gsub()
命令返回已进行的替换数,这意味着它将返回原始第四个字段中存在的斜杠数。如果没有,该函数返回零,这将导致记录不是被打印。
您是否还想确保第三个字段是'Y'
或'N'
,您可以使用
awk -F '|' -v query="'ABC'" -v yn="^'[YN]'$" '
BEGIN { OFS = FS }
$1 == query && $3 ~ yn && gsub("/","",$4)' file
在这里,我们将第三个字段需要匹配的正则表达式传递给变量awk
,yn
然后使用它来$3 ~ yn
执行我们的测试。该表达式^'[YN]'$
匹配'Y'
或'N'
。
答案2
使用sed
$ sed -En "\~^('ABC[^YN]*(Y|N)'\|'[[:alpha:]]+)/~s//\1/p" input_file
'ABC'|filler|'Y'|'john1'|'text'
'ABC'|filler|'Y'|'john1'|'te/xt'
'ABC'|filler|'N'|'mary2'|'text'
答案3
你可以这样做:
$ awk 'BEGIN{FS=OFS="|"; q="\047"}
($1==q"ABC"q)&&($3~q"Y|N"q)&&($4~"/") { sub("/","",$4);print }
' test.txt
'ABC'|filler|'Y'|'john1'|'text'
'ABC'|filler|'Y'|'john1'|'te/xt'
'ABC'|filler|'N'|'mary2'|'text'
它将字段分隔符和输出字段分隔符设置为相同的值:|
。然后使用引号字符创建一个变量q="047"
(这将简化脚本的其余部分),然后测试 3 件事:
- 第一个字段完全等于
'ABC'
。 - 第三个字段是
'Y'
or'N'
。 - 第四个字段实际上包含一个
/
.
然后做:
/
删除第四个字段内的第一个。- 打印整行。
这与您在 grep 使用正则表达式测试 ABC 中发布的 grep 命令不同。如果这就是您想要的,则将 替换$1 == q"ABC"q
为$1 ~ "ABC"
或什至只是~"ABC"
(这将在整个输入行的任何位置找到 ABC)。
测试所有输入线是否具有其中一个值似乎Y
也是多余的。N
如果是这样,您可以删除第二个测试。
这可以让 awk 命令简化为:
awk '($1~/ABC/)&&sub("/","",$4)' FS="|" OFS="|" test.txt
如果您需要替换第四个字段中的所有内容,那么您可以使用/
更改函数。请注意,某些操作系统(甚至是当前的操作系统)可能会携带sub
gsub
较旧的awk
实现这可能不支持 gsub。
答案4
tr
适用于此类内容:
grep ABC test.txt | grep "$wordY|$wordN'[[:alpha:]]+/" | tr -d '/'
tr
是“translate”的缩写,允许您更改给定集中出现的任何字符,方法是删除该字符,或将其替换为另一个集中相同位置的字符。
该-d
参数选择“删除字符”模式,其中给定集合中的字符(此处该集合只是一个字符“/”)在重写到输出之前从输入中删除。
有关详细信息,请参阅man tr
。