it-roy-ru.com

Как я могу преобразовать вкладки в пробелы в каждом файле каталога?

Как я могу преобразовать вкладки в пробелы в каждом файле каталога (возможно, рекурсивно)?

Кроме того, есть ли способ установить количество пробелов на вкладке?

213
Cynede

Предупреждение: это сломает ваш репо.

Это приведет к повреждению двоичных файлов , в том числе тех, которые находятся под svn, .git! Прочитайте комментарии перед использованием!

find . -type f -exec sed -i.orig 's/\t/ /g' {} +

Исходный файл сохраняется как [filename].orig.

Недостатки:

  • Заменим вкладки везде в файле.
  • Это займет много времени, если в этом каталоге окажется дамп SQL объемом 5 ГБ.
61
Martin Beckett

Простая замена на sed - это нормально, но не самое лучшее решение. Если между вкладками есть «лишние» пробелы, они все равно останутся после замены, поэтому поля будут неровными. Вкладки, развернутые в середине строки, также не будут работать правильно. В bash мы можем сказать вместо

find . -name '*.Java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;

применить expand к каждому файлу Java в текущем дереве каталогов. Удалите/замените аргумент -name, если вы ориентируетесь на некоторые другие типы файлов. Как упоминается в одном из комментариев, будьте очень осторожны при удалении -name или использовании слабого подстановочного знака. Вы можете легко забить хранилище и другие скрытые файлы без намерения. Вот почему первоначальный ответ включал это:

Вы должны всегда делать резервную копию дерева, прежде чем пытаться что-то подобное на случай, если что-то пойдет не так.

316
Gene

Попробуйте инструмент командной строки expand .

expand -i -t 4 input | sponge output

где

  • -i используется для разворачивания только ведущих вкладок в каждой строке;
  • -t 4 означает, что каждая вкладка будет преобразована в 4 символа пробела (по умолчанию 8).
  • sponge входит в пакет moreutils и избегает очистки входного файла .

Наконец, вы можете использовать gexpand в OSX после установки coreutils с помощью Homebrew (brew install coreutils).

174
kev

Сбор лучших комментариев из ответа Джина , наилучшее решение на сегодняшний день, это использование sponge из moreutils

Sudo apt-get install moreutils
# The complete one-liner:
find ./ -iname '*.Java' -type f -exec bash -c 'expand -t 4 "$0" | sponge "$0"' {} \;

Объяснение: 

  • ./ рекурсивно ищет из текущего каталога
  • -iname - это нечувствительное к регистру совпадение (как для *.Java, так и для *.Java)
  • type -f находит только обычные файлы (без каталогов, двоичных файлов или символических ссылок)
  • -exec bash -c выполнить следующие команды в подоболочке для каждого имени файла, {}
  • expand -t 4 расширяет все табуляции до 4 пробелов
  • sponge впитывает стандартный ввод (из expand) и записывает в файл (тот же) *. 

NOTE: * Простое перенаправление файлов (> "$0") здесь не сработает, потому что слишком скоро перезапишет файл .

Advantage: все исходные права доступа к файлам сохраняются, и никакие промежуточные tmp файлы не используются.

16
not2qubit

Используйте обратную косую черту sed.

На Linux:

  • Замените все вкладки с 1 дефисом во всех файлах * .txt:

    sed -i $'s/\t/-/g' *.txt
    
  • Замените все вкладки на 1 пробел на месте, во всех файлах * .txt:

    sed -i $'s/\t/ /g' *.txt
    
  • Замените все вкладки с 4 пробелами во всех файлах * .txt:

    sed -i $'s/\t/    /g' *.txt
    

На маке:

  • Замените все вкладки с 4 пробелами во всех файлах * .txt:

    sed -i '' $'s/\t/    /g' *.txt
    
14
e9t

Мне нравится приведенный выше пример поиска для рекурсивного приложения. Чтобы адаптировать его как нерекурсивный, изменяя только файлы в текущем каталоге, которые соответствуют шаблону, расширения глобуса оболочки может быть достаточно для небольшого количества файлов:

ls *.Java | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh -v

Если вы хотите, чтобы он замолчал после того, как вы уверены, что он работает, просто отбросьте -v в конце команды sh.

Конечно, вы можете выбрать любой набор файлов в первой команде. Например, перечислите только определенный подкаталог (или каталоги) контролируемым образом, например:

ls mod/*/*.php | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh

Или, в свою очередь, запустите find (1) с некоторой комбинацией параметров глубины и т.д .:

find mod/ -name '*.php' -mindepth 1 -maxdepth 2 | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh
3
drchuck

Вы можете использовать общедоступную команду pr (man-страница здесь ). Например, чтобы преобразовать вкладки в четыре пробела, сделайте это:

pr -t -e=4 file > file.expanded
  • -t подавляет заголовки
  • -e=num расширяет вкладки до num пробелов

Чтобы рекурсивно преобразовать все файлы в дереве каталогов, пропуская двоичные файлы:

#!/bin/bash
num=4
shopt -s globstar nullglob
for f in **/*; do
  [[ -f "$f" ]]   || continue # skip if not a regular file
  ! grep -qI "$f" && continue # skip binary files
  pr -t -e=$num "$f" > "$f.expanded.$$" && mv "$f.expanded.$$" "$f"
done

Логика для пропуска двоичных файлов от этот пост .

НОТА:

  1. Это может быть опасно в git или svn repo
  2. Это неправильное решение, если у вас есть файлы кода, в которых вкладки встроены в строковые литералы
3
codeforester

Как я могу преобразовать вкладки в пробелы в каждом файле каталога (возможно Рекурсивно)?

Обычно это не, что вы хотите.

Вы хотите сделать это для изображений PNG? PDF файлы? Каталог .git? Ваша Makefile (какие требуются вкладки)? SQL-дамп объемом 5 ГБ?

Теоретически вы можете передать множество параметров исключения в find или что-то еще , Что вы используете; но это хрупко и сломается, как только вы добавите другие двоичные файлы

То, что вы хотите, это как минимум:

  1. Пропустить файлы определенного размера.
  2. Определите, является ли файл двоичным, проверив наличие байта NULL.
  3. Заменяйте только вкладки в start файла (expand делает это, sed Нет).

Насколько я знаю, не существует "стандартной" утилиты Unix, которая могла бы сделать это, и это не очень легко сделать с однострочником Shell, поэтому необходим скрипт.

Некоторое время назад я создал небольшой скрипт с именем sanitize_files , который делает именно Это. Также исправлены некоторые другие распространенные вещи, такие как замена \r\n на \n, Добавление завершающего \n и т.д.

Вы можете найти упрощенный сценарий без дополнительных функций и аргументов командной строки ниже, но я Рекомендую использовать вышеупомянутый сценарий, так как он с большей вероятностью получит исправления ошибок и Другие обновленные, чем этот пост ,.

Я также хотел бы отметить, в ответ на некоторые другие ответы здесь, , Что использование Shell globbing является not надежным способом сделать это, потому что раньше .__ или позже вы в конечном итоге с большим количеством файлов, чем уместится в ARG_MAX (в современных системах Linux это 128 КБ, что может показаться большим, но рано или поздно этого не достаточно).


#!/usr/bin/env python
#
# http://code.arp242.net/sanitize_files
#

import os, re, sys


def is_binary(data):
    return data.find(b'\000') >= 0


def should_ignore(path):
    keep = [
        # VCS systems
        '.git/', '.hg/' '.svn/' 'CVS/',

        # These files have significant whitespace/tabs, and cannot be edited
        # safely
        # TODO: there are probably more of these files..
        'Makefile', 'BSDmakefile', 'GNUmakefile', 'Gemfile.lock'
    ]

    for k in keep:
        if '/%s' % k in path:
            return True
    return False


def run(files):
    indent_find = b'\t'
    indent_replace = b'    ' * indent_width

    for f in files:
        if should_ignore(f):
            print('Ignoring %s' % f)
            continue

        try:
            size = os.stat(f).st_size
        # Unresolvable symlink, just ignore those
        except FileNotFoundError as exc:
            print('%s is unresolvable, skipping (%s)' % (f, exc))
            continue

        if size == 0: continue
        if size > 1024 ** 2:
            print("Skipping `%s' because it's over 1MiB" % f)
            continue

        try:
            data = open(f, 'rb').read()
        except (OSError, PermissionError) as exc:
            print("Error: Unable to read `%s': %s" % (f, exc))
            continue

        if is_binary(data):
            print("Skipping `%s' because it looks binary" % f)
            continue

        data = data.split(b'\n')

        fixed_indent = False
        for i, line in enumerate(data):
            # Fix indentation
            repl_count = 0
            while line.startswith(indent_find):
                fixed_indent = True
                repl_count += 1
                line = line.replace(indent_find, b'', 1)

            if repl_count > 0:
                line = indent_replace * repl_count + line

        data = list(filter(lambda x: x is not None, data))

        try:
            open(f, 'wb').write(b'\n'.join(data))
        except (OSError, PermissionError) as exc:
            print("Error: Unable to write to `%s': %s" % (f, exc))


if __== '__main__':
    allfiles = []
    for root, dirs, files in os.walk(os.getcwd()):
        for f in files:
            p = '%s/%s' % (root, f)
            if do_add:
                allfiles.append(p)

    run(allfiles)
3
Martin Tournoij

Чтобы рекурсивно преобразовать все файлы Java в каталоге, чтобы использовать 4 пробела вместо вкладки:

find . -type f -name *.Java -exec bash -c 'expand -t 4 {} > /tmp/stuff;mv /tmp/stuff {}' \;
2
Raffi Khatchadourian

Загрузите и запустите следующий сценарий для рекурсивного преобразования жестких вкладок в программные вкладки в текстовых файлах.

Выполните сценарий из папки, которая содержит текстовые файлы.

#!/bin/bash

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

Тело не упомянуто rpl? Используя rpl вы можете заменить любую строку. Чтобы преобразовать вкладки в пробелы,

rpl -R -e "\t" "    "  .

очень просто.

1
PeopleMoutainPeopleSea

Я использовал astyle , чтобы переопределить весь мой код C/C++ после нахождения смешанных табуляций и пробелов. У этого также есть варианты, чтобы принудить определенный стиль скобки, если вы хотите.

1
Theo Belaire

Использование expand, как предлагается в других ответах, кажется наиболее логичным подходом для этой задачи в одиночку.

Тем не менее, это также может быть сделано с Bash и Awk на случай, если вы захотите сделать некоторые другие модификации вместе с ним.

Если вы используете Bash 4.0 или выше, встроенную shoptglobstar можно использовать для рекурсивного поиска с помощью **.

С GNU Awk версии 4.1 или более новой, можно внести изменения, подобные «inplace» файла:

shopt -s globstar
gawk -i inplace '{gsub("\t","    ")}1' **/*.ext

Если вы хотите установить количество пробелов на вкладке:

gawk -i inplace -v n=4 'BEGIN{for(i=1;i<=n;i++) c=c" "}{gsub("\t",c)}1' **/*.ext
1
John B

Я рекомендую использовать:

find . -name '*.lua' -exec ex '+%s/\t/  /g' -cwq {} \;

Комментарии:

  1. Используйте в месте редактирования. Храните резервные копии в VCS. Нет необходимости создавать * .orig файлы. Хорошей практикой является сравнение результата с вашим последним коммитом, чтобы убедиться, что в любом случае это работает должным образом.
  2. sed - это потоковый редактор. Используйте ex для редактирования на месте. Это позволяет избежать создания дополнительных временных файлов и порождать оболочки для каждой замены, как в top answer
  3. ВНИМАНИЕ: Это портит все вкладки, а не только те, которые используются для отступа. Также он не делает контекстную замену вкладок. Этого было достаточно для моего варианта использования. Но не может быть приемлемым для вас.
  4. Правка: более ранняя версия этого ответа использовала find|xargs вместо find -exec. Как указывает @ gniourf-gniourf, это приводит к проблемам с пробелами, кавычками и контрольными символами в именах файлов cf. Уилер .
1
Heinrich Hartmann

Для этого можно использовать vim:

find -type f \( -name '*.css' -o -name '*.html' -o -name '*.js' -o -name '*.php' \) -execdir vim -c retab -c wq {} \;

Как заявил Carpetsmoker, он будет перезагружен в соответствии с вашими настройками vim. И моделины в файлах, если есть. Также он заменит вкладки не только в начале строк. Что не то, что вы обычно хотите. Например, у вас могут быть литералы, содержащие вкладки.

0
x-yuri

Для этого вы можете использовать find с tabs-to-spaces package.

Сначала установите tabs-to-spaces

npm install -g tabs-to-spaces

затем запустите эту команду из корневого каталога вашего проекта;

find . -name '*' -exec t2s --spaces 2 {} \;

Это заменит каждый символ tab на 2 spaces в каждом файле.

0
Harsh Vakharia

Git дружественный метод хранилища

git-tab-to-space() (
  d="$(mktemp -d)"
  git grep --cached -Il '' | grep -E "${1:-.}" | \
    xargs -I'{}' bash -c '\
    f="${1}/f" \
    && expand -t 4 "$0" > "$f" && \
    chmod --reference="$0" "$f" && \
    mv "$f" "$0"' \
    '{}' "$d" \
  ;
  rmdir "$d"
)

Действовать на все файлы в текущем каталоге:

git-tab-to-space

Действовать только с файлами C или C++:

git-tab-to-space '\.(c|h)(|pp)$'

Вы, вероятно, хотите этого особенно из-за тех раздражающих Makefiles, которые требуют вкладок.

Команда git grep --cached -Il '':

  • перечисляет только отслеживаемые файлы, поэтому внутри .git ничего нет
  • исключает каталоги, двоичные файлы (будут повреждены) и символические ссылки (будут преобразованы в обычные файлы)

как объяснено в: Как перечислить все текстовые (недвоичные) файлы в репозитории git?

chmod --reference сохраняет права доступа к файлу без изменений: https://unix.stackexchange.com/questions/20645/clone-ownership-and-permissions-from-another-file К сожалению, я не могу найти краткую альтернативу POSIX .

Если ваша кодовая база имела безумную идею разрешить функциональные необработанные вкладки в строках, используйте:

expand -i

а затем получайте удовольствие, просматривая все незапуски линейных вкладок одну за другой, которые вы можете перечислить с помощью: Можно ли использовать git grep для вкладок?

Проверено на Ubuntu 18.04.