Как я могу конвертировать вкладки в пробелы в каждом файле каталога (возможно, рекурсивно)?
Кроме того, существует ли способ задать количество пробелов на вкладку?
Как я могу конвертировать вкладки в пробелы в каждом файле каталога (возможно, рекурсивно)?
Кроме того, существует ли способ задать количество пробелов на вкладку?
Предупреждение: это нарушит ваше репо.
Этот приведет к повреждению двоичных файлов, в том числе в
svn
,.git
! Прочитайте комментарии перед использованием!
find . -type f -exec sed -i.orig 's/\t/ /g' {} +
Исходный файл сохраняется как [filename].orig
.
Downsides:
Простая замена с помощью sed
в порядке, но не наилучшим возможным решением. Если между вкладками есть "лишние" пробелы, они все равно будут присутствовать после замены, поэтому поля будут оборваны. Вкладки, развернутые в середине строк, также будут работать неправильно. В bash
мы можем сказать вместо этого
find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
применить expand
к каждому файлу Java в текущем дереве каталогов. Удалите/замените аргумент -name
, если вы настроили таргетинг на другие типы файлов. Как отмечается в одном из замечаний, будьте очень осторожны при удалении -name
или использовании слабого шаблона. Вы можете легко сбрасывать репозиторий и другие скрытые файлы без намерения. Вот почему исходный ответ включал это:
Вы всегда должны делать резервную копию дерева, прежде чем пытаться что-то вроде этого, если что-то пойдет не так.
Попробуйте инструмент командной строки expand
.
expand -i -t 4 input | sponge output
где
-i
используется для расширения только ведущих вкладок в каждой строке;-t 4
означает, что каждая вкладка будет преобразована в 4 символа пробела (по умолчанию 8).sponge
находится из moreutils
и избегает очистки входного файла.Наконец, вы можете использовать gexpand
в OSX после установки coreutils
с помощью Homebrew (brew install coreutils
).
Использовать обратную косую черту sed
.
В linux:
Замените все вкладки 1 дефисом inplace во всех файлах *.txt:
sed -i $'s/\t/-/g' *.txt
Замените все вкладки на 1 место внутри, во всех *.txt файлах:
sed -i $'s/\t/ /g' *.txt
Замените все вкладки четырьмя пробелами внутри всех *.txt файлов:
sed -i $'s/\t/ /g' *.txt
На mac:
Замените все вкладки четырьмя пробелами внутри всех *.txt файлов:
sed -i '' $'s/\t/ /g' *.txt
Собирая лучшие комментарии от Ответ на гены, лучшим решением на сегодняшний день является использование 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
расширяет все TAB до 4 пробеловsponge
впитайте стандартный ввод (из expand
) и напишите в файл (тот же) *. ПРИМЕЧАНИЕ: * Простое перенаправление файлов (> "$0"
) здесь не будет работать, потому что слишком быстро перезапишет файл.
Преимущество: все исходные разрешения файлов сохраняются и не используются промежуточные файлы tmp
.
Мне нравится пример "найти" выше для рекурсивного приложения. Чтобы адаптировать его к нерекурсивному, только изменение файлов в текущем каталоге, которое соответствует шаблону, расширение оболочки оболочки может быть достаточным для небольших объемов файлов:
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
Как конвертировать вкладки в пробелы в каждом файле каталога (возможно рекурсивно)?
Обычно это не, что вы хотите.
Вы хотите сделать это для png-изображений? PDF файлы? Каталог .git? Ваш
Makefile
(для чего нужны вкладки)? 5-мегабайтный SQL-дамп?
Вы могли бы теоретически передать множество опций исключения для find
или что-то еще
иначе вы используете; но это хрупко и будет разорваться, как только вы добавите другое
двоичные файлы.
Что вы хотите, по крайней мере:
expand
делает это, sed
не делает).Насколько мне известно, не существует "стандартной" утилиты Unix, которая может это сделать, и это не очень просто сделать с однострочным оболочкой, поэтому нужен script.
Некоторое время назад я создал немного script, называемый
sanitize_files, который точно
что. Он также фиксирует некоторые другие распространенные вещи, такие как замена \r\n
на \n
,
добавление завершающего \n
и т.д.
Вы можете найти упрощенный script без дополнительных функций и аргументов командной строки ниже, но я рекомендуем использовать вышеприведенный script, поскольку он скорее получит исправления и другой обновлен, чем этот пост.
Я также хотел бы отметить, что в ответ на некоторые другие ответы здесь,
что использование globbing оболочки не - это надежный способ сделать это, потому что раньше
или позже вы получите больше файлов, чем будет в ARG_MAX
(на современном
Linux-системы это 128k, что может показаться много, но рано или поздно это не
достаточно).
#!/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 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 __name__ == '__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)
Я использовал astyle
для повторного ввода всего кода на C/С++ после поиска смешанных вкладок и пробелов. У него также есть опции, чтобы форсировать особый стиль фигурной скобки, если хотите.
Моя рекомендация:
find . -name '*.lua' -exec ex '+%s/\t/ /g' -cwq {} \;
Комментарии:
sed
- редактор потока. Используйте ex
для редактирования на месте. Это позволяет избежать создания дополнительных временных файлов и нерестовых оболочек для каждой замены, как в верхнем ответе.find|xargs
вместо find -exec
. Как указано в @gniourf-gniourf, это приводит к проблемам с пробелами, кавычками и контрольными символами в именах файлов ср. Wheeler.Чтобы преобразовать все файлы Java рекурсивно в каталог, чтобы использовать 4 пробела вместо закладки:
find . -type f -name *.java -exec bash -c 'expand -t 4 {} > /tmp/stuff;mv /tmp/stuff {}' \;
Загрузите и запустите следующий script, чтобы рекурсивно преобразовать жесткие вкладки в мягкие вкладки в текстовые файлы.
Выполните script из папки, содержащей текстовые файлы.
#!/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;
Вы можете использовать общедоступную команду pr
(справочная страница здесь). Например, чтобы преобразовать вкладки в четыре пробела, сделайте следующее:
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
Логика для пропуска двоичных файлов от этого сообщения.
Примечание:
Для этого можно использовать vim
:
find -type f \( -name '*.css' -o -name '*.html' -o -name '*.js' -o -name '*.php' \) -execdir vim -c retab -c wq {} \;
Как заявил Carpetsmoker, он будет retab в соответствии с вашими настройками vim
. И моделирует файлы, если они есть. Кроме того, он заменит вкладки не только в начале строк. Это не то, что вы обычно хотите. Например, у вас могут быть литералы, содержащие вкладки.
Если вы хотите заменить вкладки на пробелы, например, файлы *.c и *.h, следующая команда - лучшая:
find . -name "*.c" -o -name "*.h" | xargs -IFILE -t bash -c " expand -t 4 FILE > tmp ; cat tmp > FILE"
Тогда rm -f tmp
Вы можете использовать find
с tabs-to-spaces
для этого.
Сначала установите tabs-to-spaces
npm install -g tabs-to-spaces
тогда запустите эту команду из корневого каталога вашего проекта;
find . -name '*' -exec t2s --spaces 2 {} \;
Это заменит каждый символ tab
на 2 spaces
в каждом файле.
Преобразование вкладок в пространство только в файлах ".lua" [вкладки → 2 пробела]
find . -iname "*.lua" -exec sed -i "s#\t# #g" '{}' \;
Использование expand
, как было предложено в других ответах, кажется наиболее логичным для этой задачи.
Тем не менее, это также можно сделать с помощью Bash и Awk, если вы захотите сделать некоторые другие модификации вместе с ним.
При использовании Bash 4.0 или выше shopt builtin globstar
может использоваться для рекурсивного поиска с помощью **
.
С GNU Awk версии 4.1 или выше, sed, например, "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
Используйте vim-way:
$ ex +'bufdo retab' -cxa **/*.*
globstar
(**
) для рекурсии, активируйте shopt -s globstar
.**/*.c
.Чтобы изменить tabstop, добавьте +'set ts=2'
.
Однако нижняя сторона - это замена вкладок внутри строк.
Итак, для немного лучшего решения (с помощью замены) попробуйте:
$ ex -s +'bufdo %s/^\t\+/ /ge' -cxa **/*.*
Или с помощью утилиты ex
editor + expand
:
$ ex -s +'bufdo!%!expand -t2' -cxa **/*.*
Для конечных пробелов см.: Как удалить конечные пробелы для нескольких файлов?
Вы можете добавить следующую функцию в свой .bash_profile
:
# Convert tabs to spaces.
# Usage: retab *.*
# See: https://stackoverflow.com/q/11094383/55075
retab() {
ex +'set ts=2' +'bufdo retab' -cxa $*
}
Если вы не против использования notepad ++ или подобного программного обеспечения, откройте все упомянутые файлы в блокноте ++, затем перейдите на вкладку замены (shortcut ctrl + h)
выберите регулярное выражение или расширенный режим поиска, теперь он отображает \t, помещает его в поиск и помещает любое количество пробелов, которое вы хотите заменить, щелкните по замене всех открытых документов.
заменить вкладку пробелом в блокноте ++
Существует также альтернатива, которая может лучше соответствовать вашим потребностям, вы можете сделать это на вкладке "Найти файлы", выбрать каталог и выбрать определенные файлы с помощью фильтра типов, а остальные - как раньше.