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

是否有像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 


评论

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

#1 楼

awk '{=;print}'

或更短:

awk '{=};1'


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

之所以行之有效,是因为当您将某些内容分配给一个字段时,awk通过将所有字段(print,...,)与$NF(以空格分隔)连接来重建整个记录(由OFS打印)默认值)。

1(以及其他可能的空白字符,取决于语言环境和awk的实现)

评论


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

–布赖恩
2015年11月3日,19:18

@Brian,不,那个;在标准awk语法中是必需的

–StéphaneChazelas
2015年11月3日在22:07



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

–布赖恩
2015年11月3日在22:21

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

–用户友好
17年6月23日在1:12



回声“你好” | xargs

– JREAM
18年4月3日在10:32

#2 楼

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

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


示例

这是上面的命令。

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


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

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


字符classes

您还可以使用字符类名称,而不用像这样逐字列出这些集合,sed

$ 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


请改用这些类文字集总是看起来很浪费空间,但是如果您担心代码的可移植性,或者不得不处理其他字符集(请考虑国际性的话),那么您可能会想使用类名。 br />
参考文献


sed常见问题解答的第3节


评论


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

–奥利维尔·杜拉克(Olivier Dulac)
13年11月21日在12:44



sed的“ s / ^ [\ t] * //”不可移植。通常,POSIX甚至要求删除空格,反斜杠或t字符的序列,而当POSIXLY_CORRECT在环境中时,GNU sed也会这样做。

–StéphaneChazelas
16年8月11日14:56



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

–尤金·比尤科夫(Eugene Biryukov)
18年6月1日在8:54



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

–托尼
18年6月25日在23:13



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

–托尼
18年6月25日在23:27

#3 楼

不带参数的xargs可以执行此操作。

示例:

trimmed_string=$(echo "no_trimmed_string" | xargs) 


评论


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

–roaima
2015年9月9日在16:04

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

–don_crissti
2015年9月9日18:28

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

–roaima
2015年9月9日19:22

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

–StéphaneChazelas
19年5月21日在17:19

#4 楼

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

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


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

chmod +x /usr/local/bin/trim


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

cat file | trim



(以下注释:我之前曾用过:while read i; do echo "$i"; done
也可以用,但性能较差)

评论


如果您的文件很大和/或包含反斜杠,请祝您好运。

–don_crissti
2014年12月31日下午1:31

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

–rubo77
2014年12月31日上午10:42

您必须在读取-r行时使用反斜线以保留反斜线,即使如此....关于大文件/速度,实际上,您选择了最差的解决方案。我认为没有什么更糟的了。请参阅“为什么使用Shell循环处理文本不良做法”中的答案?包括我对最后一个答案的评论,并在其中添加了速度基准链接。 sed的答案在这里是非常好的IMO,远胜于阅读。

–don_crissti
2014年12月31日12:24在

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

–StéphaneChazelas
2015年5月27日14:52

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

–杰夫·克莱顿(Jeff Clayton)
2015年11月20日在16:26



#5 楼

如果将行存储为变量,则可以使用bash来执行以下操作:

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

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


删除尾随字符串中的空格:

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


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

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


评论


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

–催眠
18年3月24日在16:04

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

–peterh-恢复莫妮卡
18年7月5日在13:56



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

–user1683793
18年7月10日在22:54

#6 楼

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


如果要将行读入shell变量,则read会执行此操作,除非另有说明。

评论


+1阅读。因此,如果您在读取时通过管道传输到它,则可以正常工作:cat file |一边读我回显$ i;完成

–rubo77
13年11月21日在3:36



@rubo,除了在您的示例中,shell还会重新处理未引用的变量。使用echo“ $ i”查看读取的真实效果

–roaima
2015年9月9日19:19



#7 楼

要使用“管道”工具删除给定行中的所有前导和尾随空格,我可以确定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'
A B C


awk删除前导和尾部空格,并将其压缩到单个空格


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


在这种情况下,sed删除前导空格和尾部空格而不会碰到单词之间的任何空格。 />
备注:

如果每行只有一个单词,则tr会起作用。

评论


尽管这些都不会修剪尾随/领先的换行符

– pronebird
16年11月29日在12:50

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

–托尼
18年6月25日在23:15

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

–托尼
18年6月25日在23:28

@highmaintenance:对于命令tr使用[:space:]而不是[:blank:],例如:... | tr -d [:space:],也可以删除换行符。 (请参阅:man tr)

– tron5
19年8月9日在13:52



#8 楼

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上)!

#9 楼

一目了然的答案:

#!/usr/bin/env python3
import sys
for line in sys.stdin: print(line.strip()) 


奖金:用任意字符替换str.strip([chars])可以修剪或根据需要使用.lstrip().rstrip()

像rubo77的答案一样,另存为脚本/usr/local/bin/trim并使用chmod +x授予权限。

#10 楼

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

    trim(){
        echo $@
    }

    a="     some random string   "

    echo ">>`trim $a`<<"
Output
>>some random string<<


#11 楼

我使用awk编写了这个shell函数,在开始将设置记录分隔为
之前,一开始就是使用awk

awkcliptor(){
    awk -e 'BEGIN{ RS="^$" } {gsub(/^[\n\t ]*|[\n\t ]*$/,"");print ;exit}' "" ; } 


BEGIN{ RS="^$" }
首先,即将整个输入分隔为空白as
单个记录

gsub(this,that)
用该字符串替换此正则表达式

/^[\n\t ]*|[\n\t ]*$/:该字符串的
捕获任何前置换行符空间和制表符类
或发布换行符和制表符类,并用
空字符串

print;exit替换它们:然后打印并退出

""
并通过awk传递要处理的函数的第一个参数

使用方法:
复制上面的代码,粘贴到shell中,然后输入要
定义函数。
然后可以使用awkcliptor作为带有第一个参数的命令作为输入文件

示例用法:

echo '
 ggggg    

      ' > a_file
awkcliptor a_file


输出:

ggggg




echo -e "\n ggggg    \n\n      "|awkcliptor 


输出:

ggggg


评论


您能解释一下awk'{$ 1 = $ 1}; 1'的区别吗?

–rubo77
20年1月31日在9:35

#12 楼

对于我们这些大脑中没有足够空间来记住晦涩的sed语法的人,只需反转字符串,用空格定界符剪切第一个字段,然后再次将其反转。
cat file | rev | cut -d' ' -f1 | rev


评论


只有在每行的开头不超过一个空格且任何行中的一个单词不超过一个单词的情况下,此方法才有效。

– mttpgn
20-10-27在23:09

#13 楼

trimpy () {
    python3 -c 'import sys
for line in sys.stdin: print(line.strip())'
}
trimsed () {
gsed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'
}
trimzsh () {
   local out="$(</dev/stdin)"
   [[ "$out" =~ '^\s*(.*\S)\s*$' ]] && out="$match[1]"  || out=''
   print -nr -- "$out"
}
# example usage
echo " hi " | trimpy

奖金:用任意字符替换str.strip([chars])进行修剪或根据需要使用.lstrip().rstrip()

#14 楼

翻译命令会起作用

cat file | tr -d [:blank:]


评论


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

–布莱恩·红胡子
18-09-28在16:41

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

– Anthony Rutledge
19年5月18日23:37

#15 楼

对于bash示例:
alias trim="awk '{$1=$1};1'"

echo -e  "    hello\t\tkitty   " | trim | hexdump  -C

00000000  68 65 6c 6c 6f 20 6b 69  74 74 79 0a              |hello kitty.|
0000000c


评论


awk'{$ 1 = $ 1}; 1'的答案是很久以前给出的。几乎从很早以前就提出了使用别名进行别名的想法。是的,您可以发表别人的评论并将其转变为答案。但是,如果您这样做了,则应该对之前发表过创意的人表示赞赏。而且,这是对已接受答案的如此细微的扩展,以至于真的不值得费心。

–斯科特
20-09-4在4:08



想法是取别名。我以前没有看到这个答案。

– Marek Lisiecki
20年9月5日在18:13

还有第二件事:“感谢您的反馈!信誉低于15的人的投票将被记录下来,但不要更改公开显示的帖子分数。”

– Marek Lisiecki
20年9月5日在18:25