如何修剪某些输出的每一行的前导和尾随空格?


153

我想从输出的每一行中删除所有前导和尾随空格和制表符。

有没有像trim我可以将输出通过管道输入的简单工具?

示例文件:

test space at back 
 test space at front
TAB at end  
    TAB at front
sequence of some    space in the middle
some empty lines with differing TABS and spaces:





 test space at both ends 

1
对于任何在这里寻找删除换行符的解决方案的人来说,这是一个不同的问题。根据定义,换行符会创建新的文本行。因此,一行文本不能包含换行符。您要问的问题是如何从字符串的开头或结尾删除换行符:stackoverflow.com/questions/369758,或者如何删除空白行或仅包含空格的行:serverfault.com/questions/252921
托尼

Answers:


198
awk '{$1=$1;print}'

或更短:

awk '{$1=$1};1'

将修剪前导和尾随空格或制表符1 ,还将制表符和空格序列压缩到一个空格中。

之所以行之有效,是因为当您向某个字段分配某项内容时,通过将所有字段(,...,)与(默认为空格)连接起来,可以awk重建整个记录(由打印)。print$1$NFOFS

1(可能还有其他空白字符,具体取决于语言环境和awk实现)


2
第二个例子中的分号是多余的。可以使用:awk '{$1=$1}1'
Brian


有趣的... gawk,mawk和OS X的awk不支持分号。(至少对于我的版本(分别为1.2、4.1.1和20070501))
Brian

1
对于这种方法,我唯一不喜欢的是您会丢失行内的重复空格。例如,echo -e 'foo \t bar' | awk '{$1=$1};1'
user.friendly

2
echo ' hello ' | xargs
JREAM '18 -4-3

43

如果您使用的是GNU,则命令可以像这样压缩sed

$ sed 's/^[ \t]*//;s/[ \t]*$//' < file

这是上面的命令。

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
blahblah

您可以hexdump用来确认sed命令是否正确剥离了所需的字符。

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//' | hexdump -C
00000000  62 6c 61 68 62 6c 61 68  0a                       |blahblah.|
00000009

角色类

您也可以使用字符类名称,而不是像这样逐字列出这些集合[ \t]

$ sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//' < file

$ echo -e " \t   blahblah  \t  " | sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'

大多数使用正则表达式(regex)的GNU工具都支持这些类。

 [[:alnum:]]  - [A-Za-z0-9]     Alphanumeric characters
 [[:alpha:]]  - [A-Za-z]        Alphabetic characters
 [[:blank:]]  - [ \x09]         Space or tab characters only
 [[:cntrl:]]  - [\x00-\x19\x7F] Control characters
 [[:digit:]]  - [0-9]           Numeric characters
 [[:graph:]]  - [!-~]           Printable and visible characters
 [[:lower:]]  - [a-z]           Lower-case alphabetic characters
 [[:print:]]  - [ -~]           Printable (non-Control) characters
 [[:punct:]]  - [!-/:-@[-`{-~]  Punctuation characters
 [[:space:]]  - [ \t\v\f]       All whitespace chars
 [[:upper:]]  - [A-Z]           Upper-case alphabetic characters
 [[:xdigit:]] - [0-9a-fA-F]     Hexadecimal digit characters

使用这些而不是文字集似乎总是在浪费空间,但是如果您担心代码的可移植性,或者不得不处理其他字符集(请考虑国际性的话),那么您可能会想使用类名代替。

参考文献


请注意,这[[:space:]]并不等同[ \t]于一般情况(unicode等)。[[:space:]]可能会慢得多(因为unicode中的空白类型比just ' '和还要多'\t')。其他所有东西都一样。
Olivier Dulac

sed 's/^[ \t]*//'不便携。Atually POSIX甚至要求删除空格,反斜杠或序列t的人物,这就是GNU sed的时候也确实POSIXLY_CORRECT是在环境中。
斯特凡Chazelas

如果要修剪换行符怎么办?'\ n \ n文字\ n \ N'
尤金Biryukov

我喜欢sed解决方案,因为缺少awk解决方案中的其他副作用。当我现在在OSX jsut的bash中尝试它时,第一个变体不起作用,但是字符类版本确实起作用:sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
Tony

@EugeneBiryukov看到我对原始帖子的评论
Tony

23

正如StéphaneChazelas在接受的答案中所建议的那样,您现在可以
创建一个脚本/usr/local/bin/trim

#!/bin/bash
awk '{$1=$1};1'

并赋予该文件可执行权限:

chmod +x /usr/local/bin/trim

现在,您可以将每个输出传递trim给例如:

cat file | trim

(对于下面的评论:我以前用过:while read i; do echo "$i"; done
它也可以正常工作,但是性能较低)


1
如果您的文件很大和/或包含反斜杠,则祝您好运。
don_crissti 2014年

1
@don_crissti:您还能发表点意见吗?哪种解决方案更适合大型文件?如果文件包含反斜杠,该如何解决?
rubo77

3
你必须使用while read -r line保存反斜线和甚至然后...。至于大文件/速度,实际上,您选择了最差的解决方案。我认为没有什么更糟的了。请参阅“ 为什么使用Shell循环处理文本不良做法”中的答案包括我对最后一个答案的评论,并在其中添加了速度基准的链接。在sed这里的答案是IMO完美的罚款,并远不如read
don_crissti 2014年

@don_crissti ...和/或具有-以1个或多个e,E或n个字符的组合开头和之后的行,和/或包含NUL字符。同样,最后一个换行符之后的非终止行也将被跳过。
斯特凡Chazelas

1
您还可以在/ etc / profile中添加别名(或〜/ .bashrc或〜/ .zshrc等...)别名trim =“ awk'{\ $ 1 = \ $ 1}; 1'”
Jeff Clayton

22

不带参数的xargs可以这样做。

例:

trimmed_string=$(echo "no_trimmed_string" | xargs) 

1
这还会在一行中压缩多个空格,这在问题中没有要求
roaima

1
@roaima-是的,但是接受的答案也会压缩空格(问题中没有要求)。我认为真正的问题是,xargs如果输入包含反斜杠和单引号,则将无法传递。
don_crissti

但是,@ don_crissti并不意味着所接受的答案正确地回答了所问的问题。但是在这种情况下,它并没有被标记为警告,而在公认的答案中却是。希望我已经强调了这个事实,以防它与将来的读者有关。
roaima 2015年

它还会在单引号,双引号和反斜杠字符上中断。它还运行一个或多个echo调用。一些回显实现也将处理选项和/或反斜杠...这也仅适用于单行输入。
斯特凡Chazelas

17
sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'

如果要将行读入shell变量,除非另有说明,否则read已经这样做了。


1
为+1 read。因此,如果您在阅读时通过管道传送它有效:cat file | while read i; do echo $i; done
rubo77

1
@rubo,除了在您的示例中,shell还会重新处理未引用的变量。使用echo "$i"见到的真实效果read
roaima

13

如果将行存储为变量,则可以使用bash来完成工作:

从字符串中删除前导空格:

shopt -s extglob
echo ${text##+([[:space:]])}

从字符串中删除结尾的空格:

shopt -s extglob
echo ${text%%+([[:space:]])}

从字符串中删除所有空格:

echo ${text//[[:space:]]}

从字符串中删除所有空白与删除前导和尾随空格(如上所述)不同。
catpnosis

迄今为止最好的解决方案-它仅需要bash内置函数,而无需外部进程派生。
彼得

2
真好 如果脚本不需要引入外部程序(例如awk或sed),则它们可以更快地运行很多。这也适用于ksh的“现代”(93u +)版本。
user1683793

9

要使用“管道”工具删除给定行中的所有前导和尾随空格,我可以确定3种不完全等效的方式。这些差异关系到输入行字之间的间隔。根据预期的行为,您将做出选择。

例子

为了解释差异,请考虑以下虚拟输入行:

"   \t  A   \tB\tC   \t  "

TR

$ echo -e "   \t  A   \tB\tC   \t  " | tr -d "[:blank:]"
ABC

tr确实是一个简单的命令。在这种情况下,它将删除任何空格或制表符。

awk

$ echo -e "   \t  A   \tB\tC   \t  " | awk '{$1=$1};1'
A B C

awk 删除前导和尾部空格,并将单词之间的每个空格压缩到单个空格。

sed

$ echo -e "   \t  A   \tB\tC   \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
A       B   C

在这种情况下,sed删除前导空格和尾部空格而不会触及单词之间的任何空格。

备注:

如果每行只有一个单词,tr则可以完成此工作。


不过
不能削减

+1显示具有(有时是意外的)输出的解决方案列表。
托尼

@ user61382,这已经很晚了,但是请参阅我对原始帖子的评论。
托尼

@highmaintenance:[:space:]对命令tr(如:)使用,而不是[:blank:] ... | tr -d [:space:]来删除换行符。(参见:man tr
tron5

6

sed是一个很棒的工具:

                        # substitute ("s/")
sed 's/^[[:blank:]]*//; # parts of lines that start ("^")  with a space/tab 
     s/[[:blank:]]*$//' # or end ("$") with a space/tab
                        # with nothing (/)

您可以在案文中用管道将其用于您的情况,例如

<file sed -e 's/^[[...

或者如果您sed是GNU ,则对其进行“内联”处理:

sed -i 's/...' file

但是以这种方式更改源是“危险的”,因为在无法正常工作(甚至不能正常工作!)时,它可能无法恢复,因此请先进行备份(或使用-i.bak也可以移植到某些BSD上的好处sed) !


2

翻译命令会起作用

cat file | tr -d [:blank:]

4
此命令不正确,因为它会从文件中删除所有空格,而不仅仅是前导/尾随空格。
Brian Redbeard

@BrianRedbeard你是正确的。对于没有空格的整体字符串,这仍然是一个有用的答案。
Anthony Rutledge

0

如果要修剪的字符串短且连续/连续,则可以将其作为参数传递给任何bash函数:

    trim(){
        echo $@
    }

    a="     some random string   "

    echo ">>`trim $a`<<"
Output
>>some random string<<
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.