在Linux中用制表符替换空格

118

如何在Linux中将给定文本文件中的空格替换为制表符?

11个回答

190

使用 unexpand(1) 程序


UNEXPAND(1)                      User Commands                     UNEXPAND(1)

NAME
       unexpand - convert spaces to tabs

SYNOPSIS
       unexpand [OPTION]... [FILE]...

DESCRIPTION
       Convert  blanks in each FILE to tabs, writing to standard output.  With
       no FILE, or when FILE is -, read standard input.

       Mandatory arguments to long options are  mandatory  for  short  options
       too.

       -a, --all
              convert all blanks, instead of just initial blanks

       --first-only
              convert only leading sequences of blanks (overrides -a)

       -t, --tabs=N
              have tabs N characters apart instead of 8 (enables -a)

       -t, --tabs=LIST
              use comma separated LIST of tab positions (enables -a)

       --help display this help and exit

       --version
              output version information and exit
. . .
STANDARDS
       The expand and unexpand utilities conform to IEEE Std 1003.1-2001
       (``POSIX.1'').

5
哇,我从未知道“expand/unexpand”的存在。我试图做相反的事情,使用“expand”很完美,而不必去折腾tr或者sed - Ibrahim
4
记录一下,"expand/unexpand"是标准工具。您可以在此链接(http://pubs.opengroup.org/onlinepubs/009695299/utilities/unexpand.html)上查看。 - kojiro
5
这些都是标准化的真不错。我喜欢“UNIX哲学”。如果能原地操作就更好了。 - Matthew Flaschen
3
我不认为unexpand在这里适用。它只能转换开头的空格,而且只有两个或更多的空格才能转换。请参见此处:http://lists.gnu.org/archive/html/bug-textutils/2001-01/msg00025.html - olala
17
注意:unexpand 不能将单个空格转换为制表符。如果您需要盲目地将所有连续的0x20字符转换为单个制表符,则需要使用另一个工具。 - Steve S.
显示剩余8条评论

54

我认为你可以尝试使用awk

awk -v OFS="\t" '$1=$1' file1

如果您喜欢,也可以使用SED。
sed 's/[:blank:]+/,/g' thefile.txt > the_modified_copy.txt

甚至是tr元素
tr -s '\t' < thefile.txt | tr '\t' ' ' > the_modified_copy.txt

或者采用Sam Bisbee建议的简化版tr解决方案。
tr ' ' \\t < someFile > someFile

4
在你的sed示例中,最佳实践要求你使用tr替换单字符以提高效率/速度。此外,tr示例可以更容易地使用以下方式:tr ' ' \\t < someFile > someFile - Sam Bisbee
2
当然,tr比sed性能更好,但我热爱Unix的主要原因是有很多做事情的方式。如果您计划多次进行此替换,您将寻找具有良好性能的解决方案,但如果您只打算执行一次,则会寻找涉及让您感到舒适的命令的解决方案。 - Jonathan
2
我不得不使用试错法使sed工作。我不知道为什么我必须像这样转义加号:ls -l | sed "s/ \+/ /g" - Jess
通过使用 awk -v OFS="\t" '$1=$1' file1 命令,我发现如果你有一个以数字0开头的行(例如 0 1 2),那么这一行将会从结果中被省略。 - Nikola Novak
@Jess 你找到了“正确的默认语法”正则表达式。默认情况下,sed将单个(未转义)加号视为简单字符。对于一些其他字符,如'?'等也是如此。您可以在此处找到更多信息:https://www.gnu.org/software/sed/manual/html_node/Extended-regexps.html#Extended-regexps。类似的语法细节可以在此处找到(请注意,这是grep的man,而不是sed):http://www.gnu.org/software/grep/manual/grep.html#Basic-vs-Extended。 - Victor Yarema
我该如何以递归的方式实现这个? - Aaron Franke

15

使用Perl

perl -p -i -e 's/ /\t/g' file.txt

3
曾经遇到过将连续的空格替换为单个制表符的类似问题。在Perl中,只需在正则表达式中添加一个“+”即可解决。 - Todd
当然,我想做相反的事情:将制表符转换为两个空格:perl -p -i -e 's/\t/ /g' *.java - TimP
我可以递归地做这个吗? - Aaron Franke
这是唯一对我有效的变体;我使用了s/ {4}/将4个空格缩进转换为制表符。 - CrazyPyro

14
更好的 tr 命令: 命令的改进:
tr [:blank:] \\t

这将清理输出,例如 unzip -l ,以便进一步使用 grep、cut 等进行处理。
例如,
unzip -l some-jars-and-textfiles.zip | tr [:blank:] \\t | cut -f 5 | grep jar

1
我不必使用引号来使其工作:tr [:blank:] \\t - Ömer An

3

将当前目录下的每个 .js 文件转换为 Tab 的示例命令(只转换前导空格):

find . -name "*.js" -exec bash -c 'unexpand -t 4 --first-only "$0" > /tmp/totabbuff && mv /tmp/totabbuff "$0"' {} \;

在Windows 7上使用Cygwin测试通过。 - arkod

3

下载并运行以下脚本,以递归方式将软制表符转换为硬制表符在纯文本文件中。

将脚本放置在包含纯文本文件的文件夹内并从该文件夹内执行。

#!/bin/bash

find . -type f -and -not -path './.git/*' -exec grep -Iq . {} \; -and -print | while read -r file; do {
    echo "Converting... "$file"";
    data=$(unexpand --first-only -t 4 "$file");
    rm "$file";
    echo "$data" > "$file";
}; done;

2
这将把连续的空格替换为一个空格(但不包括制表符)。
tr -s '[:blank:]'

这将用制表符替换连续的空格。
tr -s '[:blank:]' '\t'

实际上,使用 -c 选项会替换连续的非空格字符。 - wingedsubmariner
1
这个问题是关于选项卡的,这不是一个答案。 - Matthew Read

2

使用 sed

T=$(printf "\t")
sed "s/[[:blank:]]\+/$T/g"

或者

sed "s/[[:space:]]\+/$T/g"

1
你也可以使用astyle。我发现它非常有用,并且还有几个选项:
Tab and Bracket Options:
   If  no  indentation  option is set, the default option of 4 spaces will be used. Equivalent to -s4 --indent=spaces=4.  If no brackets option is set, the
   brackets will not be changed.

   --indent=spaces, --indent=spaces=#, -s, -s#
          Indent using # spaces per indent. Between 1 to 20.  Not specifying # will result in a default of 4 spaces per indent.

   --indent=tab, --indent=tab=#, -t, -t#
          Indent using tab characters, assuming that each tab is # spaces long.  Between 1 and 20. Not specifying # will result in a default assumption  of
          4 spaces per tab.`

0
sed 's/[[:blank:]]\+/\t/g' original.out > fixed_file.out

例如,这将减少制表符或空格的数量为一个单一的制表符。

您还可以将多个空格/制表符的情况转换为一个空格:

sed 's/[[:blank:]]\+/ /g' original.out > fixed_file.out

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接