Удалить конечные пробелы рекурсивно только в конце файла, используя grep / sed? - PullRequest
1 голос
/ 18 января 2011

По сути, у меня есть около 1500 файлов, и последний символ любого из этих файлов не должен быть пробелом любого типа.

Как проверить несколько файлов, чтобы убедиться, что они не заканчиваются каким-либо пробелом? (Перевод строки, пробел, возврат каретки, табуляция и т. Д.)?

Ответы [ 9 ]

3 голосов
/ 18 января 2011
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:

Вот все, что нужноРешение, которое читает файл только один раз.Он накапливает только пустые строки способом, аналогичным приведенному выше команде 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 (единственное число)
  • добавлены комментарии
2 голосов
/ 18 января 2011

Это уберет все конечные пробелы:

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

Вероятно, есть эквивалент в sed, но я гораздо лучше знаком с Perl, надеюсь, он вам подходит.Основная идея: если следующим символом является пробел, сохраните его;в противном случае выведите любые сохраненные символы, за которыми следует только что прочитанный символ.Если мы нажмем EOF после прочтения одного или нескольких пробельных символов, они не будут напечатаны.

Это просто обнаружит конечные пробельные символы и даст код выхода 1, если так: [РЕДАКТИРОВАТЬ] Выше описано, как обнаружить или изменить один файл.Если у вас есть большое дерево каталогов, содержащее файлы, к которым вы хотите применить изменения, вы можете поместить команду в отдельный скрипт:

fix.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».(Было бы неплохо сначала проверить это на небольшом тестовом наборе файлов.)

1 голос
/ 19 января 2011

Вы также можете использовать 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)
1 голос
/ 19 января 2011
ruby -e 's=ARGF.read;s.rstrip!;print s' file

в основном, прочитайте весь файл, удалите последний пробел, если есть, и распечатайте содержимое. Так что это решение не для очень больших файлов.

1 голос
/ 19 января 2011

Решение 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/
}
1 голос
/ 18 января 2011

Может быть легче читать файл снизу вверх:

tac filename | 
awk '
    /^[[:space:]]*$/ && !seen {next} 
    /[^[:space:]]/   && !seen {gsub(/[[:space:]]+$/,""); seen=1}
    seen
' | 
tac
0 голосов
/ 19 января 2011

Использование 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)
0 голосов
/ 18 января 2011

Просто для удовольствия, вот простой ответ 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;
}

Не намного дольше, чем Решение Денниса по awk , и, смею сказать, оно легче для понимания! : -Р

0 голосов
/ 18 января 2011

Версия 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, а затем Tab в оболочке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...