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

rub*_*o77 265 pipe shell-script text-processing whitespace

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

有没有一个简单的工具,比如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 
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 337

awk '{$1=$1;print}'
Run Code Online (Sandbox Code Playgroud)

或更短:

awk '{$1=$1};1'
Run Code Online (Sandbox Code Playgroud)

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

这是有效的,因为当您为其中一个字段分配某些内容时,通过将所有字段 ( , ..., ) 与(默认情况下为空格) 连接起来,awk重建整个记录(如 打印的那样)。print$1$NFOFS

也删除空行,将其更改为awk '{$1=$1};NF'(其中NF讲述awk仅打印记录其中N的赭Fields不为零)。千万不能这样做awk '$1=$1',因为有时候建议作为,这也将删除线,其第一场是任何陈述0所支持awk000-0e+12...)

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

  • @Brian,[不,标准awk 语法中需要`;`](http://austingroupbugs.net/view.php?id=226#c2226) (15认同)
  • 第二个例子的分号是多余的。可以使用:`awk '{$1=$1}1'` (4认同)
  • 我不喜欢这种方法的唯一一件事是您会丢失行内的重复空格。例如,`echo -e 'foo \t bar' | awk '{$1=$1};1'` (4认同)
  • `回声'你好' | xargs` (4认同)

slm*_*slm 81

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

$ sed 's/^[ \t]*//;s/[ \t]*$//' < file
Run Code Online (Sandbox Code Playgroud)

例子

这是上面的命令在起作用。

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
blahblah
Run Code Online (Sandbox Code Playgroud)

您可以使用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
Run Code Online (Sandbox Code Playgroud)

字符类

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

$ sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//' < file
Run Code Online (Sandbox Code Playgroud)

例子

$ echo -e " \t   blahblah  \t  " | sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
Run Code Online (Sandbox Code Playgroud)

大多数使用正则表达式 (regex) 的 GNU 工具都支持这些类(这里有它们在基于 ASCII 的系统的典型 C 语言环境中的等效项(并且仅在那里))。

 [[:alnum:]]  - [A-Za-z0-9]     Alphanumeric characters
 [[:alpha:]]  - [A-Za-z]        Alphabetic characters
 [[:blank:]]  - [ \t]           Space or tab characters only
 [[:cntrl:]]  - [\x00-\x1F\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\n\r]   All whitespace chars
 [[:upper:]]  - [A-Z]           Upper-case alphabetic characters
 [[:xdigit:]] - [0-9a-fA-F]     Hexadecimal digit characters
Run Code Online (Sandbox Code Playgroud)

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

参考

  • 我喜欢 sed 解决方案,因为它不像 awk 解决方案那样有其他副作用。当我现在在 OSX 上的 bash 中尝试时,第一个变体不起作用,但字符类版本确实起作用: `sed 's/^[[:blank:]]*//;s/[[:blank:] ]*$//'` (2认同)

小智 41

没有参数的 xargs 做到这一点。

例子:

trimmed_string=$(echo "no_trimmed_string" | xargs) 
Run Code Online (Sandbox Code Playgroud)

  • 这也会在一行中收缩多个空格,这在问题中没有要求 (6认同)
  • @roaima - 是的,但接受的答案也挤压了空间(问题中没有要求)。我认为这里真正的问题是,如果输入包含反斜杠和单引号,“xargs”将无法传递。 (3认同)
  • 它还会在单引号、双引号、反斜杠字符处中断。它还运行一个或多个“echo”调用。一些 echo 实现还将处理选项和/或反斜杠...这也仅适用于单行输入。 (2认同)

rub*_*o77 31

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

#!/bin/bash
awk '{$1=$1};1'
Run Code Online (Sandbox Code Playgroud)

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

chmod +x /usr/local/bin/trim
Run Code Online (Sandbox Code Playgroud)

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

cat file | trim
Run Code Online (Sandbox Code Playgroud)

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

  • 你必须使用`while read -r line`来保留反斜杠和[即使这样......](http://unix.stackexchange.com/questions/176490/echoing-stdin-when-running-an-ed1 -script/176514#comment292069_176502)。至于大文件/速度,真的,你选择了最糟糕的解决方案。我不认为那里有更糟糕的事情。请参阅 [Why is using a shell loop to process text bad practice ?](http://unix.stackexchange.com/q/169716) 上的答案,包括我对最后一个答案的评论,其中我添加了速度基准的链接。这里的 `sed` 答案在 IMO 中非常好,远比 `read` 好。 (4认同)
  • 您还可以在 /etc/profile(或您的 ~/.bashrc 或 ~/.zshrc 等)中添加别名 alias trim="awk '{\$1=\$1};1'" (3认同)
  • 不需要`bash`,你可以用`#! /usr/bin/awk -f``{$1=$1};1`。(注意包含 `=` 字符的文件名) (3认同)
  • @don_crissti:你能多评论一点吗?哪个解决方案更适合大文件,如果文件包含反斜杠,我该如何修改我的解决方案? (2认同)
  • 请注意,它必须在 2 行上,一行用于 she-bang,另一行用于代码 (`{$1=$1};1`)。 (2认同)

Łuk*_*hel 24

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

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

shopt -s extglob
printf '%s\n' "${text##+([[:space:]])}"
Run Code Online (Sandbox Code Playgroud)

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

shopt -s extglob
printf '%s\n' "${text%%+([[:space:]])}"
Run Code Online (Sandbox Code Playgroud)

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

printf '%s\n' "${text//[[:space:]]}"
Run Code Online (Sandbox Code Playgroud)

  • 迄今为止最好的解决方案 - 它只需要 bash 内置命令,不需要外部进程分支。 (5认同)
  • 好的。如果脚本不需要引入外部程序(例如 awk 或 sed),它们的运行速度会快很多。这也适用于 ksh 的“现代”(93u+) 版本。 (2认同)

小智 22

由于“管道”工具,为了从给定行中删除所有前导和尾随空格,我可以确定 3 种不完全等效的不同方式。这些差异涉及输入行单词之间的空格。根据预期的行为,您将做出选择。

例子

为了解释差异,让我们考虑这个虚拟输入行:

"   \t  A   \tB\tC   \t  "
Run Code Online (Sandbox Code Playgroud)

tr

$ echo -e "   \t  A   \tB\tC   \t  " | tr -d "[:blank:]"
ABC
Run Code Online (Sandbox Code Playgroud)

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

awk

$ echo -e "   \t  A   \tB\tC   \t  " | awk '{$1=$1};1'
A B C
Run Code Online (Sandbox Code Playgroud)

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

sed

$ echo -e "   \t  A   \tB\tC   \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
A       B   C
Run Code Online (Sandbox Code Playgroud)

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

评论:

在每行一个单词的情况下,tr完成这项工作。


Gil*_*il' 19

sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'
Run Code Online (Sandbox Code Playgroud)

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

  • @rubo,除了在您的示例中,未加引号的变量也由 shell 重新处理。使用 echo "$i" 查看 read 的真实效果 (2认同)

qwr*_*qwr 10

一个你一看就明白的答案:

#!/usr/bin/env python3
import sys
for line in sys.stdin: print(line.strip()) 
Run Code Online (Sandbox Code Playgroud)

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

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

  • 我通常不喜欢脚本中的 python,但与这些答案中的所有其他咒语相比,这是迄今为止最清晰的脚本之一。 (2认同)

Ant*_*dge 7

您将把它添加到您的小 Bash 库中。我几乎可以打赌!这样做的好处是不会在输出末尾添加换行符echo,就像丢弃预期输出一样。此外,这些解决方案是可重用的,不需要修改 shell 选项,可以与管道内联调用,并且符合 posix 标准。这是迄今为止最好的答案。根据您的喜好进行修改。

使用 测试输出od -cb,其他一些解决方案可能希望对其输出执行某些操作。

顺便说一句:正确的量词是+,而不是*,因为您希望在 1 个或多个空白字符上触发替换!

ltrim(您可以通过管道输入)

function ltrim ()
{
    sed -E 's/^[[:space:]]+//'
}
Run Code Online (Sandbox Code Playgroud)

rtrim(您可以通过管道输入)

function rtrim ()
{
    sed -E 's/[[:space:]]+$//'
}
Run Code Online (Sandbox Code Playgroud)

修剪(两全其美,是的,你可以通过管道传输)

function trim ()
{
    ltrim | rtrim
}
Run Code Online (Sandbox Code Playgroud)


Mic*_*ant 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 (/)
Run Code Online (Sandbox Code Playgroud)

您可以将它用于您的案例,或者在文本中使用管道,例如

<file sed -e 's/^[[...
Run Code Online (Sandbox Code Playgroud)

或者,如果您sed是 GNU 用户,则通过“内联”对其进行操作:

sed -i 's/...' file
Run Code Online (Sandbox Code Playgroud)

但是以这种方式更改源是“危险的”,因为当它不能正常工作时(甚至当它正常工作时)它可能无法恢复,所以首先备份(或使用-i.bak它也有利于移植到某些 BSD seds) !