1

基本上,我有大约 1,500 个文件,这些文件的最后一个字符不应该是任何类型的空格。

如何检查一堆文件以确保它们不会以某种形式的空格结尾?(换行符、空格、回车符、制表符等)?

4

9 回答 9

3
awk '{if (flag) print line; line = $0; flag = 1} END {gsub("[[:space:]]+$","",line); printf line}'

编辑:

新版本:

sed命令删除仅包含空格的所有尾随行,然后该awk命令删除结束换行符。

sed '/^[[:space:]]*$/{:a;$d;N;/\n[[:space:]]*$/ba}' inputfile |
    awk '{if (flag) print line; line = $0; flag = 1} END {printf line}'

缺点是它读取文件两次。

编辑2:

这是一个只读取文件一次的全 awk 解决方案。它以类似于上述sed命令的方式累积仅包含空格的行。

#!/usr/bin/awk -f

# accumulate a run of white-space-only lines so they can be printed or discarded
/^[[:space:]]*$/ {
    accumlines = accumlines nl $0
    nl = "\n"
    accum = 1
    next
}

# print the previous line and any accumulated lines, store the current line for the next pass
{
    if (flag) print line
    if (accum) { print accumlines; accum = 0 }
    accumlines = nl = ""
    line = $0
    flag = 1
}

# print the last line without a trailing newline after removing all trailing whitespace
# the resulting output could be null (nothing rather than 0x00)
# note that we're not print the accumulated lines since they're part of the 
# trailing white-space we're trying to get rid of
END {
    gsub("[[:space:]]+$","",line)
    printf line
}

编辑3:

  • 删除了不必要的BEGIN子句
  • 更改lines为,accumlines以便更容易区分line(单数)
  • 添加评论
于 2011-01-18T18:01:47.727 回答
2

这将删除所有尾随空格:

perl -e '$s = ""; while (defined($_ = getc)) { if (/\s/) { $s .= $_; } else { print $s, $_; $s = ""; } }' < infile > outfile

可能有一个等价物,sed但我对 Perl 更熟悉,希望对你有用。基本思路:如果下一个字符是空格,则保存;否则,打印任何保存的字符,后跟刚刚读取的字符。如果我们在读取一个或多个空白字符后点击 EOF,它们将不会被打印。

这将简单地检测尾随空格,如果是,则给出退出代码 1:

perl -e 'while (defined($_ = getc)) { $last = $_; } exit($last =~ /\s/);' < infile > outfile

[编辑] 上面描述了如何检测或更改单个文件。如果您有一个包含要应用更改的文件的大型目录树,则可以将命令放在单独的脚本中:

修复.pl

#!/usr/bin/perl
$s = "";
while (defined($_ = getc)) {
    if (/\s/) { $s .= $_; } else { print $s, $_; $s = ""; }
}

并将其与find命令结合使用:

find /top/dir -type f -exec sh -c 'mv "{}" "{}.bak" && fix.pl < "{}.bak" > "{}"' ';'

这会将每个原始文件移动到以“.bak”结尾的备份文件中。(最好先在一个小的测试文件集上测试它。)

于 2011-01-18T17:59:18.597 回答
1

从底部到顶部读取文件可能更容易:

tac filename | 
awk '
    /^[[:space:]]*$/ && !seen {next} 
    /[^[:space:]]/   && !seen {gsub(/[[:space:]]+$/,""); seen=1}
    seen
' | 
tac
于 2011-01-18T19:01:31.773 回答
1

只是为了好玩,这是一个简单的 C 答案:

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    int c, bufsize = 100, ns = 0;
    char *buf = malloc(bufsize);

    while ((c = getchar()) != EOF) {
        if (isspace(c)) {
            if (ns == bufsize) buf = realloc(buf, bufsize *= 2);
            buf[ns++] = c;
        } else {
            fwrite(buf, 1, ns, stdout);
            ns = 0;
            putchar(c);
        }
    }

    free(buf);
    return 0;
}

不比Dennis 的 awk 解决方案长多少,而且,我敢说,它更容易理解!:-P

于 2011-01-18T20:18:20.180 回答
1

Perl 解决方案:

# command-line arguments are the names of the files to check.
# output is names of files that end with trailing whitespace
for (@ARGV) {
  open F, '<', $_;
  seek F, -1, 2;                # seek to before last char in file
  print "$_\n" if <F> =~ /\s/
}
于 2011-01-18T22:08:23.070 回答
1
ruby -e 's=ARGF.read;s.rstrip!;print s' file

基本上,读取整个文件,如果有的话,去掉最后一个空格,然后打印出内容。所以这个解决方案不适用于非常大的文件。

于 2011-01-19T00:32:54.810 回答
1

您还可以使用man ed删除文件末尾的尾随空白并man dd删除最后一个换行符(尽管请记住 ed 将整个文件读入内存并执行就地编辑而无需任何类型的先前备份):

# tested on Mac OS X using Bash
while IFS= read -r -d $'\0' file; do
   # remove white space at end of (non-empty) file
   # note: ed will append final newline if missing
   printf '%s\n' H '$g/[[:space:]]\{1,\}$/s///g' wq | ed -s "${file}"
   printf "" | dd  of="${file}" seek=$(($(stat -f "%z" "${file}") - 1)) bs=1 count=1
   #printf "" | dd  of="${file}" seek=$(($(wc -c < "${file}") - 1)) bs=1 count=1
done < <(find -x "/path/to/dir" -type f -not -empty -print0)
于 2011-01-19T15:42:51.177 回答
0

版本 2。Linux 语法。正确的命令。

find /directory/you/want -type f | \ 
xargs --verbose -L 1 sed -n --in-place -r \
':loop;/[^[:space:]\t]/ {p;b;}; N;b loop;'  

版本 1. 删除每行末尾的空格。FreeBSD 语法。

find /directory/that/holds/your/files -type f | xargs -L 1  sed  -i '' -E 's/[:         :]+$//'

其中的空白[: :]实际上由一个空格和一个制表符组成。有了空间,这很容易。你只需按下空格键。为了插入制表符,请按 Ctrl-V,然后在 shell 中按 Tab。

于 2011-01-18T19:48:25.647 回答
0

man dd不使用man ed

while IFS= read -r -d $'\0' file; do
   filesize="$(wc -c < "${file}")"
   while [[ $(tail -c 1 "${file}" | tr -dc '[[:space:]]' | wc -c) -eq 1 ]]; do
      printf "" | dd  of="${file}" seek=$(($filesize - 1)) bs=1 count=1
      let filesize-=1
   done
done < <(find -x "/path/to/dir" -type f -not -empty -print0)
于 2011-01-19T16:24:44.590 回答