Как преобразовать табуляции в пробелы в каждом файле каталога (возможно, рекурсивно)?
Кроме того, есть ли способ установить количество пробелов на вкладку?
Как преобразовать табуляции в пробелы в каждом файле каталога (возможно, рекурсивно)?
Кроме того, есть ли способ установить количество пробелов на вкладку?
Предупреждение: это нарушит ваше репо.
Это повредит двоичные файлы, в том числе под
svn
,.git
! Прочтите комментарии перед использованием!
find . -iname '*.java' -type f -exec sed -i.orig 's/\t/ /g' {} +
Исходный файл сохраняется как [filename].orig
.
Замените '* .java' окончанием файла того типа, который вы ищете. Таким образом вы можете предотвратить случайное повреждение двоичных файлов.
Минусы:
find ./ -type f -exec sed -i 's/^\t/####/g' {} \;
. Но я не знал о команде расширения - очень полезно!
- person Martin Konecny; 07.05.2014
#
, возможно, потребуется заменить фактическими пробелами, я предполагаю, что это означает пробелы # в ответе. Но ^
не помогает: вы заменяете только первую вкладку, последующие вкладки не будут заменены, т.е. бесполезны!
- person Sander Verhagen; 06.11.2014
sed
- совершенно неподходящий инструмент для этой задачи.
- person Sven; 30.03.2015
find
не отфильтровала по расширению файла и, таким образом, поразила каждый файл без разбора.
- person mtraceur; 26.02.2021
Простая замена на sed
- это нормально, но не лучшее решение. Если между вкладками есть «лишние» пробелы, они останутся там после замены, поэтому поля будут неровными. Вкладки, развернутые посередине строк, также будут работать некорректно. Вместо bash
мы можем сказать
find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
применить expand
к каждому файлу Java в текущем дереве каталогов. Удалите / замените аргумент -name
, если вы ориентируетесь на другие типы файлов. Как упоминается в одном из комментариев, будьте очень осторожны при удалении -name
или использовании слабых подстановочных знаков. Вы можете легко убрать репозиторий и другие скрытые файлы без намерения. Вот почему исходный ответ включал следующее:
Вы всегда должны делать резервную копию дерева, прежде чем пробовать что-то подобное, на случай, если что-то пойдет не так.
{}
. Похоже, он не знал о $0
, когда используется -c
. Затем dimo414 изменил использование временного интервала в каталоге преобразования на /tmp
, что будет намного медленнее, если /tmp
находится в другой точке монтирования. К сожалению, у меня нет Linux, чтобы проверить ваше $0
предложение. Но я думаю, что вы правы.
- person Gene; 26.11.2013
Don't omit the _ and try to use $0 inside the mini-script -- not only would that be more confusing, but it is also prone to failure if the filename provided by find has special meaning as an argument to the shell.
mywiki.wooledge.org/UsingFind
- person sabgenton; 30.11.2013
bash
в этом сценарии.
- person sabgenton; 30.11.2013
-c
: если Bash запускается с параметром -c, тогда $ 0 устанавливается в качестве первого аргумента после строки, которая должна быть выполнена, если таковой имеется. Похоже, они действительно хотели сделать первый аргумент доступным как $0
.
- person Gene; 30.11.2013
-c
, но, похоже, есть много хакеров, которые не рекомендуют использовать ее таким образом в данном контексте. Я не эксперт, но полагаю, что $ 1 будет пустым, если не заданы аргументы, тогда как $ 0 расширится до 'bash', что не то, что вы хотите. gniourf_gniourf не был сбит с толку или что-то в этом роде, он следовал соглашению, я не вижу причин оспаривать это.
- person sabgenton; 01.12.2013
bash -c 'echo "$0"'
без аргументов, и вы увидите, что 0 - это имя программы 'bash'. Если ваш аргумент ничего не вернул, вы все равно получите строку 'bash' в программе, зачем вам это?
- person sabgenton; 03.12.2013
./somefile bla
, а при использовании файла для сценариев bla составляет 1 доллар. Это норма :)
- person sabgenton; 05.12.2013
find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
- person Doge; 04.04.2014
bash
на вашем пути? Если нет, вы можете попробовать \bin\bash
вместо bash
в командной строке.
- person Gene; 16.04.2014
sponge
из joeyh. имя / код / moreutils, можно написать find . -name '*.py' ! -type d -exec bash -c 'expand -t 8 "$0" | sponge "$0"' {} \;
- person tokland; 09.10.2014
find . -name '*'
, я только что уничтожил свой локальный репозиторий git
- person Gautam; 22.03.2015
! -type d
на -type f
, если вы этого не хотите.
- person orestisf; 12.01.2017
find . -name '*.js' ! -type d -exec bash -c 'expand -t 2 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
- person Pencilcheck; 27.06.2017
alias tabs_to_spaces="echo 'this-url'; echo \"find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "'\"\$0\"'" > /tmp/e && mv /tmp/e "'\"\$0\"'"' {} \\;\""
, чтобы напомнить мне. Он выводит команду для запуска стиля C-c C-v.
- person Karl; 17.01.2018
.git
: find . -not -path '*/.git/*' -name '*.cs' -type f -exec bash -c 'expand -i -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
- person mja; 09.04.2018
chmod --reference
: stackoverflow.com/a/52136507/895245
- person Ciro Santilli 新疆再教育营六四事件ۍ 02.09.2018
umask
), обычно установленными в bashrc
.
- person Gene; 02.09.2018
mv
на cp
. Конечно, у вас должны быть права на запись в исходный файл.
- person Gene; 02.09.2018
*.ts
файлы ...
- person ChaseMoskal; 31.12.2019
expand
и mv
для файла, который не был преобразован. Возможно, вы сможете увидеть какое-то разрешение или аналогичную проблему. Это хорошо сработало для сотен людей, поэтому в вашем сценарии использования должно быть что-то уникальное.
- person Gene; 31.12.2019
Попробуйте инструмент командной строки expand
.
expand -i -t 4 input | sponge output
куда
-i
используется для раскрытия только ведущих вкладок в каждой строке;-t 4
означает, что каждая вкладка будет преобразована в 4 символа пробела (по умолчанию 8).sponge
взят из _ 6_ и избегает очистки входного файла.Наконец, вы можете использовать gexpand
в OSX после установки coreutils
с Homebrew (brew install coreutils
).
expand
быть установленным, поскольку он стандартизирован единой спецификацией Unix Open Group. См. Выпуск 6 за 2001 год, хотя были применены некоторые обновления, следовательно, год публикации - 2004: _ 2_
- person ; 25.07.2013
-i
в expand
, чтобы заменять только ведущие табуляции в каждой строке. Это помогает избежать замены вкладок, которые могут быть частью кода.
- person Quolonel Questions; 08.08.2014
input
- это тот же файл, что и output
, bash уничтожает содержимое еще до запуска expand
. Так работает >
.
- person Robert Siemer; 16.09.2015
sponge
, который полезен для получения стандартного вывода и перенаправления его обратно в исходный файл. Он работает, сохраняя весь вывод, поступающий на его стандартный ввод, ожидая завершения конвейера и только затем открывая и записывая исходный файл. Это часть пакета moreutils
(часто не устанавливается по умолчанию).
- person RaveTheTadpole; 08.10.2016
0600
, после использования expand
у нового файла было разрешение по умолчанию 0664
. Использование sponge
и создание нового файла имели тот же эффект. Использование sponge
и НЕ создание нового файла сохраняет исходные разрешения. Пример: expand --tabs=4 input | sponge input
. Обратите внимание на использование |
, а не >
в примере sponge
.
- person CloudNinja; 18.12.2016
Сбор лучших комментариев из ответа Джина, лучшее решение на сегодняшний день - использование 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
) и записывает в файл (тот же самый) *.ПРИМЕЧАНИЕ: * Простое перенаправление файла (> "$0"
) здесь не сработает, потому что оно слишком быстро перезапишет файл.
Преимущество: сохраняются все исходные разрешения для файлов, промежуточные tmp
файлы не используются.
Используйте экранирование обратной косой чертой sed
.
В Linux:
Замените все вкладки одним дефисом во всех файлах * .txt:
sed -i $'s/\t/-/g' *.txt
Замените все вкладки на 1 пробел во всех файлах * .txt:
sed -i $'s/\t/ /g' *.txt
Замените все вкладки на 4 пробела во всех файлах * .txt:
sed -i $'s/\t/ /g' *.txt
На Mac:
Замените все вкладки на 4 пробела во всех файлах * .txt:
sed -i '' $'s/\t/ /g' *.txt
Вы можете использовать общедоступную команду 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
Логика пропуска двоичных файлов взята из этого сообщения.
ПРИМЕЧАНИЕ.
expand
, учитывая, что оба являются POSIX? Например. есть ли у него возможность встроенного изменения? Безопасность Git по адресу: stackoverflow.com/a/52136507/895245
- person Ciro Santilli 新疆再教育营六四事件ۍ 02.09.2018
Как преобразовать табуляции в пробелы в каждом файле каталога (возможно, рекурсивно)?
Обычно это не то, что вам нужно.
Вы хотите сделать это для изображений png? PDF-файлы? Каталог .git? Ваш Makefile
(для которого требуются вкладки)? Дамп SQL на 5 ГБ?
Теоретически вы можете передать множество параметров исключения find
или чему-то еще, что вы используете; но он хрупкий и сломается, как только вы добавите другие двоичные файлы.
Вы хотите как минимум:
expand
делает это, sed
- нет).Насколько мне известно, не существует "стандартной" утилиты Unix, которая могла бы это сделать, и это не очень просто сделать с помощью однострочника оболочки, поэтому необходим сценарий.
Некоторое время назад я создал небольшой скрипт под названием sanitize_files, который делает именно это. Он также исправляет некоторые другие общие вещи, такие как замена \r\n
на \n
, добавление завершающего \n
и т. Д.
Вы можете найти упрощенный сценарий без дополнительных функций и аргументов командной строки ниже, но я рекомендую вам использовать приведенный выше сценарий, поскольку он с большей вероятностью получит исправления ошибок и другие обновления, чем это сообщение.
Я также хотел бы указать в ответ на некоторые другие ответы здесь, что использование подстановки оболочки не надежный способ сделать это, потому что рано или поздно у вас будет больше файлов чем уместится в 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 __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)
Мне нравится приведенный выше пример «найти» для рекурсивного приложения. Чтобы адаптировать его к нерекурсивному, изменяя только файлы в текущем каталоге, соответствующие подстановочному знаку, расширения оболочки оболочки может быть достаточно для небольшого количества файлов:
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
ARG_MAX
длины. В системах Linux это 128 КБ, но я сталкивался с этим пределом достаточно раз, чтобы не полагаться на подстановку оболочки.
- person Martin Tournoij; 12.08.2015
find
можно указать -maxdepth 1
, и он обрабатывает только записи изменяемого каталога, а не все дерево.
- person ShadowRanger; 30.10.2015
Я рекомендую использовать:
find . -name '*.lua' -exec ex '+%s/\t/ /g' -cwq {} \;
Комментарии:
sed
- это редактор потока. Используйте ex
для редактирования на месте. Это позволяет избежать создания дополнительных временных файлов и создания оболочек для каждой замены, как в главный ответ.find|xargs
вместо find -exec
. Как указывает @ gniourf-gniourf, это приводит к проблемам с пробелами, кавычками и управляющими символами в именах файлов cf. Wheeler.ex
может быть недоступен в каждой системе Unix. Замена на vi -e
может сработать на других машинах. Кроме того, ваше регулярное выражение заменяет любое количество начальных символов табуляции двумя пробелами. Замените регулярное выражение на +%s/\t/ /g
, чтобы не разрушать многоуровневые отступы. Однако это также влияет на символы табуляции, которые не используются для отступов.
- person Lukas Schmelzeisen; 14.06.2016
/\t/ /
для своих файлов, но выбрал /\t\+//
, чтобы не нарушать вкладки без отступов. Пропустили проблемы с несколькими отступами! Обновление ответа. [1] man7.org/linux/man -pages / man1 / ex.1p.html # SEE% C2% A0ALSO
- person Heinrich Hartmann; 14.06.2016
xargs
таким образом бесполезно, неэффективно и некорректно (подумайте о именах файлов, содержащих пробелы или кавычки). Почему бы вам вместо этого не использовать переключатель find
-exec
?
- person gniourf_gniourf; 14.06.2016
-print0
параметры для поиска / xargs. Мне нравится xargs вместо -exec
, поскольку: а) разделение задач б) его легче заменить на параллельный GNU.
- person Heinrich Hartmann; 14.06.2016
/
(поскольку я упоминал строку C, нулевой байт, конечно, запрещен). Надежный, портативный и эффективный способ - использовать -exec
: find . -name '*.lua' -exec ex '+%s/\t/ /g' -cwq {} \;
. xargs
следует использовать только в очень специфических ситуациях (которые мне еще предстоит выяснить).
- person gniourf_gniourf; 14.06.2016
-print0/-0
тоже правильно, и ИМХО чище.
- person Heinrich Hartmann; 14.06.2016
Для этого вы можете использовать find
с пакетом tabs-to-spaces
.
Сначала установите tabs-to-spaces
npm install -g tabs-to-spaces
затем запустите эту команду из корневого каталога вашего проекта;
find . -name '*' -exec t2s --spaces 2 {} \;
Это заменит каждый символ tab
на 2 spaces
в каждом файле.
Я использовал astyle
, чтобы изменить отступ всего кода C / C ++ после обнаружения смешанных табуляции и пробелов. У него также есть опции для принудительного использования определенного стиля скобок, если хотите.
Для этого можно использовать vim
:
find -type f \( -name '*.css' -o -name '*.html' -o -name '*.js' -o -name '*.php' \) -execdir vim -c retab -c wq {} \;
Как заявил Carpetsmoker, он будет изменять настройки в соответствии с вашими vim
настройками. И моделины в файлах, если есть. Также он заменит табуляции не только в начале строк. Обычно это не то, что вам нужно. Например, у вас могут быть литералы, содержащие вкладки.
:retab
изменит все вкладки в файле, а не те, что были в начале. это также зависит от ваших :tabstop
и :expandtab
настроек в vimrc или modeline, поэтому это может вообще не работать.
- person Martin Tournoij; 12.08.2015
tabstop
и expandtab
, это сработает, если вы используете vim
. Если в файлах нет строк режима.
- person x-yuri; 12.08.2015
Чтобы рекурсивно преобразовать все файлы Java в каталоге, чтобы использовать 4 пробела вместо табуляции:
find . -type f -name *.java -exec bash -c 'expand -t 4 {} > /tmp/stuff;mv /tmp/stuff {}' \;
Загрузите и запустите следующий сценарий, чтобы рекурсивно преобразовать жесткие вкладки в программные вкладки в простых текстовых файлах.
Выполните сценарий из папки, содержащей файлы с обычным текстом.
#!/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;
Удобный для репозитория метод 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)$'
Вы, вероятно, захотите этого, особенно из-за этих надоедливых файлов Makefile, которые требуют вкладок.
Команда 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.
Никто не упоминается rpl
? Используя rpl, вы можете заменить любую строку. Чтобы преобразовать табуляцию в пробелы,
rpl -R -e "\t" " " .
очень простой.
Использование expand
, как предлагается в других ответах, кажется наиболее логичным подходом только для этой задачи.
Тем не менее, это также можно сделать с помощью Bash и Awk на случай, если вы захотите внести другие изменения вместе с ним.
При использовании Bash 4.0 или более поздней версии встроенная функция shopt globstar
можно использовать для рекурсивного поиска с **
.
В GNU Awk версии 4.1 или более поздней версии sed могут быть изменены "на месте":
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
Преобразование вкладок в пространство всего в файлах ".lua" [вкладки -> 2 пробела]
find . -iname "*.lua" -exec sed -i "s#\t# #g" '{}' \;
expand -t 4 input >output
)
- person Makah; 31.03.2015
expand -t 4
расширит вкладку в a\tb
до 3 пробелов, а табуляцию в aa\tb
до 2 пробелов, как и должно быть. expand
учитывает контекст вкладки, sed
не учитывает и заменяет вкладку указанным вами количеством пробелов, независимо от контекста.
- person Sven; 31.03.2015
Используйте vim-way:
$ ex +'bufdo retab' -cxa **/*.*
globstar
(**
) для рекурсии, активируйте shopt -s globstar
.**/*.c
.Чтобы изменить позицию табуляции, добавьте +'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 $*
}
:s
команда заменит any < / i> количество вкладок с двумя пробелами (чего вы почти никогда не хотите), запускать ex только для запуска :!expand
процесса глупо ...
- person Martin Tournoij; 12.08.2015
pr
- замечательная утилита для этого. См. Этот ответ. - person codeforester   schedule 09.06.2017