仅使用'tr'替换多个空格


71

我有一个文件,f1.txt

ID     Name
1      a
2         b
3   g
6            f

空格数不是固定的。仅使用一个空格替换所有空格的最佳方法是什么tr

这是我到目前为止的内容:

cat f1.txt | tr -d " "

但是输出是:

IDName
1a
2b
3g
6f

但我希望它看起来像这样:

ID Name
1 a
2 b
3 g
6 f

请尝试避免sed


6
为什么避免sed如此重要?使用任何有效的方法!
David Richerby 2014年

7
因为我知道该怎么做sed。想知道其他方式
:)

Answers:


106

使用tr,请使用squeeze repeat选项:

$ tr -s " " < file
ID Name
1 a
2 b
3 g
6 f

或者您可以使用一种awk解决方案:

$ awk '{$2=$2};1' file
ID Name
1 a
2 b
3 g
6 f

当您更改记录中的字段时,awkrebuild $0会将所有字段合并在一起,并以分隔OFS,默认情况下为空格。

这会将空格和制表符的序列(以及其他空白字符,取决于的语言环境和实现awk)压缩到一个空格中,而且还删除了每一行的前导和尾随空格。


1
这也是一个很好的解决方案。。。我不知道现在选择哪一个:/ @Gnouc
gkmohit 2014年

随意选择您喜欢的任何解决方案,它会为您服务。请注意,我的解决方案与@polym的答案不同。
cuonglm 2014年

1
:)) 好极了!@Gnouc的答案确实是动态的,因为他使用awk,他可以做任何事情。您也可以接受他的解决方案。仅一件事:Gnouc您能否解释命令中的awk格式是什么?您还可以添加制表符/空格以使输出符合Unknown的预期输出吗?
polym

1
@polym:在Unknown的最后一次编辑中,他似乎只想要一个空格,而不希望像column -t这样输出。添加有关的说明awk
cuonglm

4
这里有一个小的差异。tr会将一行末尾的两个空格替换为一个空格。awk将删除所有尾随空格。
Anne van Rossum 2015年

19

只需使用column

column -t inputFile

输出:

ID  Name
1   a
2   b
3   g
6   f

精彩而快速的回复:)
gkmohit14 2007年

1
@Unknown很高兴为您服务:)!
polym 2014年

1
@Gnouc很棒,列也将文件作为参数。非常感谢!
polym 2014年

仅在需要时如何获得第二列?我尝试过column -t f1.txt | cut -d " " -f2 但我没有想到解决方案
gkmohit14年

2
然后使用awk:column -t file | awk '{print $2}'仅打印第二列
polym 2014年

8

如果要压缩“空白”,则需要使用tr的预定义字符集“:blank:”(水平空白标签和空格)或“:space:”(垂直空白):

/bin/echo -e  "val1\t\tval2   val3" | tr -s "[:blank:]"

示例在Red Hat 5(GNU tr)上运行。

在我的情况下,我想将所有空格标准化为一个空格,以便可以依赖于该空格作为发送器。

正如dastrobu的第二条评论所指出的,我错过了手册页中的措辞:

 -s uses the last specified SET, and occurs after translation or deletion.

这使我们消除了第一时间。工藤面对我的密集,耐心等待。

之前,从Redis config解析端口。文件:

grep "^port" $redisconf | tr "[:blank:]" " " | tr -s "[:blank:]"  | cut -d" " -f2

之后,使用挤压指定SET2:

grep "^port" $redisconf | tr -s "[:blank:]" " " | cut -d" " -f2

输出:

6379

有关覆盖空白细微差别的更多详细信息

演示当涉及到[:blank:]字符类的连续混合字符时,仅在哪里挤压失败:

 /usr/bin/printf '%s \t %s' id myname | tr -s "[:blank:]"  | od -cb
0000000   i   d      \t       m   y   n   a   m   e
        151 144 040 011 040 155 171 156 141 155 145
0000013

注意:我的两个printf格式的字符串字段由1个空格,1个制表符和1个空格分隔。挤压后,此序列仍然存在。在八进制转储的输出中,这由ascii序列040 011 040表示。


1
您真的需要tr "[:blank:]" " " | tr -s "[:blank:]"吗?我猜第一部分就足够了,即tr "[:blank:]" " "因为它规范了空白并且已经进行了替换。在手册页中:“挤压多个出现的字符[...]在所有删除和翻译完成后发生。
dastrobu

2
因此´tr -s“ [:blank:]”“”´应该做到这一点,首先将所有空格转换为空格,然后再压缩空格。无需第二个“ tr”。
dastrobu

1
我尝试了printf 'ID \t Name\n' | tr -s "[:blank:]" " " | od -cb(按照@dastrobu的建议),得到了ID Name\n(只有一个空格)作为输出。您是否真的尝试过@ user3183018?
斯科特

1
好,让我再说一次。我做了printf 'ID␣\t␣Name\n' | tr -s "[:blank:]" "␣"  (由@dastrobu建议),其中代表一个空格,我得到了ID␣Name\n(有一个空格)作为输出。这与的“ Port <SPACE> <TAB> <SPACE> 6379” 示例完全相同,只是我使用了问题的标题字符串。我想知道您是否尝试过  tr -s "[:blank:]"(没有最后一个"␣"论点)。
斯科特

1
当我这样做时printf 'ID \t Name\n' | od -cb,它确切地表明了它的预期目标ID ⁠  \t ⁠  N a m e \n(即  ID 040 011 040 N a m e\n)。同时,根据您自己的证据,您正在犯完全我所猜测的错误:您正在运行tr -s "[:blank:]"(即  tr具有一个选项和  一个参数),而不是我和@dastrobu现在已经提出四次的命令:tr -s '[:blank:]' '␣'(即,  tr具有一个选项和  两个参数)。
斯科特

5

谁需要一个程序(外壳程序除外)?

while read a b
do
    echo "$a $b"
done < f1.txt

如果您希望第二列中的值对齐(如polym的column答案),请使用printf代替echo

while read a b
do
    printf '%-2s %s\n' "$a" "$b"
done < f1.txt

1
首先,与tr相比,这在建议效率方面是非常薄弱的​​,除非输入太小而超过了tr调用的微不足道的成本-更不用说要写多少工作了。最后,您不是说这篇文章实际上并没有回答所问的问题吗?仅使用tr用一个空格替换所有空格的最佳方法是什么?
mikeserv

1
而且-您难道不容易做某事$IFS吗?也许喜欢:IFS=' <tab>' set -f ; echo $(cat <file)
mikeserv

2

这是一个古老的问题,已经解决了很多次。出于完整性考虑:我有一个类似的问题,但想通过管道将行传递给其他程序。我用了xargs

-L max-lines
   Use at most max-lines nonblank input lines per command line.
   Trailing blanks cause an input line to be logically continued 
   on the next input line.  Implies -x.

所以cat f1.txt | xargs -L1似乎输出的正是您想要的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.