在bash上使用cut和sed的奇怪行为

时间:2017-04-18 13:57:57

标签: bash sed

我有一个纯文本文件,分为2列。我想剪切每一列并用它创建一个新行,然后我想在每行的末尾添加字符串“_mystring”。

示例

包含内容的文件:

myline1 myline11 
myline2 myline22 

这将产生2个文件。

文件1:

myline1_mystring
myline2_mystring

文件2:

myline11_mystring
myline22_mystring

为此,我执行这个简单的脚本:

cat mytext.txt | cut -f $1 |sed "s/$/_mystring/" > file"$1"

所以我可以使用参数($1)执行该操作以选择列。它适用于第一列,它正在用$1替换1。但当它出现在第二列时,它会失败并且它会创建如下文件:

_mystringline1
_mystringline2

我认为这可能与cutsed命令发生的事情有关,因为我尝试了另一个sed选项来实现在最后添加字符串而且我总是得到相同的结果,但我不知道如何解决它。

修改 这里我展示了真实文件的内容:

account@for     justificar
account@for@    explicar
account@for     dar@cuentas@de
act@as  servir@de
act@as  hacer@de
act@for representar@a
act@on  reaccionar@a
act@on  actuar@sobre
act@on  responder@a
act@out representar

这里有xxd mytext.txt的结果:

00000000: 6163 636f 756e 7440 666f 7209 6a75 7374  account@for.just
00000010: 6966 6963 6172 0d0a 6163 636f 756e 7440  ificar..account@
00000020: 666f 7240 0965 7870 6c69 6361 720d 0a61  for@.explicar..a
00000030: 6363 6f75 6e74 4066 6f72 0964 6172 4063  ccount@for.dar@c
00000040: 7565 6e74 6173 4064 650d 0a61 6374 4061  uentas@de..act@a
00000050: 7309 7365 7276 6972 4064 650d 0a61 6374  s.servir@de..act
00000060: 4061 7309 6861 6365 7240 6465 0d0a 6163  @as.hacer@de..ac
00000070: 7440 666f 7209 7265 7072 6573 656e 7461  t@for.representa
00000080: 7240 610d 0a61 6374 406f 6e09 7265 6163  r@a..act@on.reac
00000090: 6369 6f6e 6172 4061 0d0a 6163 7440 6f6e  cionar@a..act@on
000000a0: 0961 6374 7561 7240 736f 6272 650d 0a61  .actuar@sobre..a
000000b0: 6374 406f 6e09 7265 7370 6f6e 6465 7240  ct@on.responder@
000000c0: 610d 0a61 6374 406f 7574 0972 6570 7265  a..act@out.repre
000000d0: 7365 6e74 6172 0d0a                      sentar..

这是hexdump -c mytext.txt

的结果
0000000   a   c   c   o   u   n   t   @   f   o   r  \t   j   u   s   t
0000010   i   f   i   c   a   r  \r  \n   a   c   c   o   u   n   t   @
0000020   f   o   r   @  \t   e   x   p   l   i   c   a   r  \r  \n   a
0000030   c   c   o   u   n   t   @   f   o   r  \t   d   a   r   @   c
0000040   u   e   n   t   a   s   @   d   e  \r  \n   a   c   t   @   a
0000050   s  \t   s   e   r   v   i   r   @   d   e  \r  \n   a   c   t
0000060   @   a   s  \t   h   a   c   e   r   @   d   e  \r  \n   a   c
0000070   t   @   f   o   r  \t   r   e   p   r   e   s   e   n   t   a
0000080   r   @   a  \r  \n   a   c   t   @   o   n  \t   r   e   a   c
0000090   c   i   o   n   a   r   @   a  \r  \n   a   c   t   @   o   n
00000a0  \t   a   c   t   u   a   r   @   s   o   b   r   e  \r  \n   a
00000b0   c   t   @   o   n  \t   r   e   s   p   o   n   d   e   r   @
00000c0   a  \r  \n   a   c   t   @   o   u   t  \t   r   e   p   r   e
00000d0   s   e   n   t   a   r  \r  \n                                
00000d8

4 个答案:

答案 0 :(得分:4)

使用awk更好

(如果在你的约束中可用)

awk '{print $1 "_mystring" > "file1";print $2 "_mystring" > "file2"}' mytext.txt

更通用:

awk -v MyStr="_mystring" '{for(i=0;i<=NF;i++) print $i MyStr > "file" i }' mytext.txt

现在是一个纯粹的sed版本:

sed -e 's/^ *//;s/ *$/_mystring/;h;s/ .*/_mystring/;w file1' -e 'x;s/.* //;w file2' -e 'd' mytext.txt

答案 1 :(得分:4)

NeronLeVelu's answerAwk中显示了一种很好的方法,但是你的解决方案的真正的问题是你没有通过去限制器用于{{ 1}},您需要使用cut开关提供。将单个空格传递给它并避免usless-use-of-cat

-d

应该解决你的问题。

以下评论表明您的去限制器是标签,您现在可以将其指定为

cut -d' ' -f "$1" mytext.txt | sed "s/$/_VERB/" > file"$1"

答案 2 :(得分:1)

如果我定义:

myscript() { cut -f$1 | sed 's/$/_VERB/' > file$1; }

并运行:

cat file | myscript 1
cat file | myscript 2
head file1 file2

我明白了:

==> file1 <==
myline1_VERB
myline2_VERB

==> file2 <==
myline11_VERB
myline22_VERB

答案 3 :(得分:1)

问题与行尾字符 cat /tmp/m1.out | awk '$1>="22:01"' 22:05:42:710 23:05:42:710 8:05:42:710 8:05:42:710 8:05:42:710 8:05:42:710 8:05:42:710 有关。我使用\r删除它们,然后一切都按预期开始工作。