Jak przekonwertować tabulatory na spacje w każdym pliku katalogu (ewentualnie rekurencyjnie)?
Czy istnieje również sposób ustawienia liczby spacji na zakładkę?
prto wspaniałe narzędzie do tego. Zobacz tę odpowiedź .
Jak przekonwertować tabulatory na spacje w każdym pliku katalogu (ewentualnie rekurencyjnie)?
Czy istnieje również sposób ustawienia liczby spacji na zakładkę?
prto wspaniałe narzędzie do tego. Zobacz tę odpowiedź .
Odpowiedzi:
Ostrzeżenie: spowoduje to uszkodzenie Twojego repozytorium.
This will uszkodzone pliki binarne , w tym osób poniżej
svn,.git! Przeczytaj komentarze przed użyciem!
find . -iname '*.java' -type f -exec sed -i.orig 's/\t/ /g' {} +
Oryginalny plik zostanie zapisany jako [filename].orig.
Zamień „* .java” na końcówkę pliku, którego szukasz. W ten sposób można zapobiec przypadkowemu uszkodzeniu plików binarnych.
Wady:
expand.
find ./ -type f -exec sed -i 's/^\t/####/g' {} \;. Ale nie wiedziałem o poleceniu rozwijania - bardzo przydatne!
Prosta wymiana sedjest w porządku, ale nie jest najlepszym możliwym rozwiązaniem. Jeśli między zakładkami znajdują się „dodatkowe” spacje, nadal będą one występować po zamianie, więc marginesy będą nierówne. Karty rozszerzone w środku linii również nie będą działać poprawnie. W bash, możemy powiedzieć, zamiast
find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
do zastosowania expanddo każdego pliku Java w bieżącym drzewie katalogów. Usuń / zamień -nameargument, jeśli celujesz na inne typy plików. Jak wspomina jeden z komentarzy, zachowaj ostrożność podczas usuwania -namelub używania słabej, wieloznacznej karty. Możesz z łatwością zamykać repozytorium i inne ukryte pliki bez intencji. Oto dlaczego pierwotna odpowiedź zawierała to:
Zawsze powinieneś wykonać kopię zapasową drzewa przed wypróbowaniem czegoś takiego na wypadek, gdyby coś poszło nie tak.
{}. Wygląda na to, że nie wiedział, $0kiedy -cjest używany. Następnie dimo414 zmienił się z mojego użycia temp w katalogu konwersji na /tmp, który będzie znacznie wolniejszy, jeśli /tmpbędzie w innym punkcie montowania. Niestety nie mam dostępnego Linux-a do przetestowania twojej $0propozycji. Ale myślę, że masz rację.
find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
spongez joeyh.name/code/moreutils , możesz napisaćfind . -name '*.py' ! -type d -exec bash -c 'expand -t 8 "$0" | sponge "$0"' {} \;
find . -name '*', właśnie zniszczyłem moje lokalne repozytorium git
Wypróbuj narzędzie wiersza polecenia expand.
expand -i -t 4 input | sponge output
gdzie
-i służy do rozwijania tylko wiodących kart w każdej linii;-t 4 oznacza, że każda karta zostanie przekonwertowana na 4 znaki białych znaków (domyślnie 8).spongepochodzi z moreutilspakietu i pozwala uniknąć czyszczenia pliku wejściowego .Wreszcie możesz korzystać gexpandz systemu OSX po instalacji za coreutilspomocą Homebrew ( brew install coreutils).
-ido, expandaby zastąpić tylko wiodące tabulatory w każdej linii. Pomaga to uniknąć zamiany kart, które mogą być częścią kodu.
inputjest tym samym plikiem, co outputbash blokuje zawartość, zanim jeszcze się uruchomi expand. Tak to >działa.
Zbieranie najlepszych komentarzy z odpowiedzi Gene'a , najlepszym jak dotąd najlepszym rozwiązaniem jest korzystanie spongez moreutils .
sudo apt-get install moreutils
# The complete one-liner:
find ./ -iname '*.java' -type f -exec bash -c 'expand -t 4 "$0" | sponge "$0"' {} \;
Wyjaśnienie:
./ rekurencyjnie szuka z bieżącego katalogu-inamejest dopasowanie bez rozróżniania wielkości liter (dla obu *.javai *.JAVApolubień)type -f znajduje tylko zwykłe pliki (bez katalogów, plików binarnych lub dowiązań symbolicznych)-exec bash -c wykonaj następujące polecenia w podpowłoce dla każdej nazwy pliku, {}expand -t 4 rozszerza wszystkie tabele do 4 pólspongewchłonąć standardowe wejście (z expand) i zapisać do pliku (tego samego) *.UWAGA : * Proste przekierowanie pliku ( > "$0") nie będzie tutaj działać, ponieważ zbyt wcześnie nadpisze plik .
Zaleta : wszystkie oryginalne uprawnienia do plików są zachowane i nie tmpsą używane żadne pliki pośrednie .
Użyj znaku odwrotnego ukośnika sed.
W systemie Linux:
Zamień wszystkie karty na 1 łącznik na miejscu we wszystkich plikach * .txt:
sed -i $'s/\t/-/g' *.txtZamień wszystkie karty na 1 miejsce w miejscu, we wszystkich plikach * .txt:
sed -i $'s/\t/ /g' *.txtZamień wszystkie tabulatory na 4 spacje we wszystkich plikach * .txt:
sed -i $'s/\t/ /g' *.txtNa komputerze Mac:
Zamień wszystkie tabulatory na 4 spacje we wszystkich plikach * .txt:
sed -i '' $'s/\t/ /g' *.txtsed -i '' $'s/\t/ /g' $(find . -name "*.txt")
Możesz użyć ogólnie dostępnego prpolecenia ( tutaj strona podręcznika ). Na przykład, aby przekonwertować tabulatory na cztery spacje, wykonaj następujące czynności:
pr -t -e=4 file > file.expanded
-t pomija nagłówki-e=numrozwija tabulatory do numspacjiAby rekurencyjnie przekonwertować wszystkie pliki w drzewie katalogów, pomijając pliki binarne:
#!/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
Logika pomijania plików binarnych pochodzi z tego postu .
UWAGA:
expandtym, że oba są POSIX? Np. Czy ma wbudowaną opcję zmiany? Git safety at: stackoverflow.com/a/52136507/895245
Jak przekonwertować tabulatory na spacje w każdym pliku katalogu (ewentualnie rekurencyjnie)?
Zwykle nie jest to, czego chcesz.
Czy chcesz to zrobić dla obrazów PNG? Pliki PDF? Katalog .git? Twój
Makefile(który wymaga zakładek)? Zrzut SQL 5 GB?
Teoretycznie możesz przekazać wiele opcji wykluczania findlub cokolwiek innego, czego używasz; ale jest to kruche i zepsuje się, gdy tylko dodasz inne pliki binarne.
Co chcesz, to co najmniej:
expandrobi to, sed
nie robi).O ile mi wiadomo, nie ma „standardowego” narzędzia uniksowego, które mogłoby to zrobić i nie jest to bardzo łatwe w przypadku powłoki jednowierszowej, więc potrzebny jest skrypt.
Jakiś czas temu stworzyłem mały skrypt o nazwie
sanitize_files, który właśnie to robi. Naprawia również kilka innych rzeczy jak zastąpienie wspólnego \r\nz \ndodanie końcowego znaku \n, itd.
Możesz znaleźć uproszczony skrypt bez dodatkowych funkcji i argumentów wiersza poleceń poniżej, ale zalecamy użycie powyższego skryptu, ponieważ jest bardziej prawdopodobne, że otrzyma poprawki błędów i inne zaktualizowane niż ten post.
Chciałbym również wskazać, w odpowiedzi na niektóre inne odpowiedzi tutaj, że użycie globowania powłoki nie jest solidnym sposobem na zrobienie tego, ponieważ wcześniej czy później skończy się więcej plików, niż zmieści się ARG_MAX(w nowoczesnych Systemy Linux to 128k, co może wydawać się dużo, ale wcześniej czy później to nie
wystarczy).
#!/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)
Podoba mi się powyższy przykład „znajdź” dla aplikacji rekurencyjnej. Aby dostosować go tak, aby nie był rekurencyjny, zmieniając tylko pliki w bieżącym katalogu, które pasują do znaku wieloznacznego, rozszerzenie globu powłoki może być wystarczające dla małych ilości plików:
ls *.java | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh -v
Jeśli chcesz to cichy po ufasz, że to działa, po prostu upuść -vna shpolecenia na końcu.
Oczywiście możesz wybrać dowolny zestaw plików w pierwszym poleceniu. Na przykład, wypisz tylko określony podkatalog (lub katalogi) w kontrolowany sposób:
ls mod/*/*.php | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh
Lub z kolei uruchom find (1) z pewną kombinacją parametrów głębokości itp .:
find mod/ -name '*.php' -mindepth 1 -maxdepth 2 | awk '{print "expand -t 4 ", $0, " > /tmp/e; mv /tmp/e ", $0}' | sh
ARG_MAXdługa. Jest to 128k w systemach Linux, ale napotkałem ten limit wystarczająco dużo razy, aby nie polegać na globowaniu powłoki.
findmożna powiedzieć -maxdepth 1, i przetwarza tylko wpisy modyfikowanego katalogu, a nie całe drzewo.
Użyłem astyledo re-indent wszyscy moi C / C ++ kod po znalezieniu mieszane kart i spacji. Ma także opcje wymuszenia określonego stylu nawiasów, jeśli chcesz.
Można vimdo tego użyć :
find -type f \( -name '*.css' -o -name '*.html' -o -name '*.js' -o -name '*.php' \) -execdir vim -c retab -c wq {} \;
Jak stwierdził Carpetsmoker, nastąpi zmiana w zależności od twoich vimustawień. I modeliny w plikach, jeśli istnieją. Ponadto zastąpi tabulatory nie tylko na początku linii. Którego na ogół nie chcesz. Na przykład możesz mieć literały zawierające tabulatory.
:retabzmieni wszystkie zakładki w pliku, a nie te na początku. zależy to również od tego, jakie są twoje ustawienia :tabstopi :expandtabustawienia w vimrc lub modeline, więc może to wcale nie działać.
tabstopi expandtab, zadziała, jeśli używasz vim. Chyba że w plikach znajdują się linie trybu.
Polecam użyć:
find . -name '*.lua' -exec ex '+%s/\t/ /g' -cwq {} \;
Komentarze:
sedjest edytorem strumieniowym. Użyj exdo edycji na miejscu. Pozwala to uniknąć tworzenia dodatkowych plików tymczasowych i odradzania powłok dla każdej zamiany, jak w pliku pierwszej odpowiedzi .find|xargszamiast find -exec. Jak wskazał @ gniourf-gniourf, prowadzi to do problemów ze spacjami, cudzysłowami i znakami kontrolnymi w nazwach plików por. Wheeler .exmoże nie być dostępny w każdym systemie Unix. Zastąpienie go vi -emoże działać na większej liczbie komputerów. Ponadto wyrażenie regularne zamienia dowolną liczbę początkowych znaków tabulacji na dwie spacje. Zamień wyrażenie regularne na, +%s/\t/ /gaby nie niszczyć wielopoziomowego wcięcia. Wpływa to jednak również na znaki tabulacji, które nie są używane do wcięcia.
/\t/ /wariantu w moich plikach, ale zdecydowałem /\t\+//się nie łamać tabulatorów bez wcięć. Pominięto problemy z wielokrotnym wcięciem! Aktualizacja odpowiedzi. [1] man7.org/linux/man-pages/man1/ex.1p.html#SEE%C2%A0ALSO
xargsw ten sposób jest bezużyteczne, nieefektywne i zepsute (pomyśl o nazwach plików zawierających spacje lub cudzysłowy). Dlaczego nie używacie find„s -execprzełącznik zamiast?
-print0opcje find / xargs. Lubię xargs -execod kiedy: a) Rozdzielenie obaw b) można łatwiej zamieniać GNU równolegle.
Aby przekonwertować rekurencyjnie wszystkie pliki Java w katalogu, tak aby używały 4 spacji zamiast tabulacji:
find . -type f -name *.java -exec bash -c 'expand -t 4 {} > /tmp/stuff;mv /tmp/stuff {}' \;
Można skorzystać findz tabs-to-spacespakietu do tego.
Najpierw zainstaluj tabs-to-spaces
npm install -g tabs-to-spaces
następnie uruchom to polecenie z katalogu głównego swojego projektu;
find . -name '*' -exec t2s --spaces 2 {} \;
Spowoduje to zastąpienie każdego tabznaku wartością 2 spacesw każdym pliku.
Nie wspomniano o ciele rpl? Za pomocą rpl możesz zamienić dowolny ciąg. Aby przekonwertować tabulatory na spacje,
rpl -R -e "\t" " " .
bardzo prosty.
Zastosowanie, expandjak sugerowano w innych odpowiedziach, wydaje się najbardziej logicznym podejściem do samego zadania.
To powiedziawszy, można to również zrobić za pomocą Bash i Awk, na wypadek, gdybyś mógł chcieć wprowadzić inne modyfikacje wraz z nim.
Jeśli używasz Bash 4.0 lub nowszego, wbudowanego shopt globstar można używać do wyszukiwania rekurencyjnego **.
W GNU Awk w wersji 4.1 lub nowszej można wprowadzać modyfikacje plików typu „inplace”:
shopt -s globstar
gawk -i inplace '{gsub("\t"," ")}1' **/*.ext
Jeśli chcesz ustawić liczbę spacji na zakładkę:
gawk -i inplace -v n=4 'BEGIN{for(i=1;i<=n;i++) c=c" "}{gsub("\t",c)}1' **/*.ext
Pobierz i uruchom następujący skrypt, aby rekurencyjnie konwertować twarde karty na miękkie karty w zwykłych plikach tekstowych.
Uruchom skrypt z folderu zawierającego zwykłe pliki tekstowe.
#!/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;
Metoda przyjazna dla repozytorium 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"
)
Działaj na wszystkie pliki w bieżącym katalogu:
git-tab-to-space
Działaj tylko na plikach C lub C ++:
git-tab-to-space '\.(c|h)(|pp)$'
Prawdopodobnie chcesz tego, szczególnie z powodu tych irytujących plików Makefile, które wymagają zakładek.
Polecenie git grep --cached -Il '':
.gitjak wyjaśniono na: Jak wyświetlić listę wszystkich plików tekstowych (niebinarnych) w repozytorium git?
chmod --referenceuprawnienia do plików pozostają niezmienione: /unix/20645/clone-ownership-and-permissions-from-another-file Niestety nie mogę znaleźć zwięzłej alternatywy POSIX .
Jeśli twoja baza kodu wpadła na szalony pomysł, aby zezwolić na funkcjonalne nieprzetworzone tabulacje w łańcuchach, użyj:
expand -i
a potem baw się dobrze, przeglądając kolejno wszystkie nie uruchamiane karty linii, które możesz wypisać: Czy można używać grep dla kart?
Testowane na Ubuntu 18.04.
Konwersja tabulatorów na spacje w plikach „.lua” [tabs -> 2 spacje]
find . -iname "*.lua" -exec sed -i "s#\t# #g" '{}' \;
expand -t 4 input >output)
expand -t 4powiększy tabulator a\tbdo 3 spacji, a tab aa\tbdo 2 spacji, tak jak powinien być. expandbierze pod uwagę kontekst karty, sednie zastępuje i zastępuje określoną przez Ciebie ilością spacji, niezależnie od kontekstu.
Użyj vim-way:
$ ex +'bufdo retab' -cxa **/*.*
globstar( **) do rekurencji, aktywuj za pomocą shopt -s globstar.**/*.c.Aby zmodyfikować tabstop, dodaj +'set ts=2'.
Jednak wadą jest to, że może zastąpić zakładki wewnątrz ciągów .
Aby uzyskać nieco lepsze rozwiązanie (przy użyciu podstawienia), spróbuj:
$ ex -s +'bufdo %s/^\t\+/ /ge' -cxa **/*.*
Lub za pomocą exedytora + expandnarzędzie:
$ ex -s +'bufdo!%!expand -t2' -cxa **/*.*
Aby zobaczyć końcowe spacje, zobacz: Jak usunąć końcowe białe spacje dla wielu plików?
Możesz dodać następującą funkcję do swojego .bash_profile:
# Convert tabs to spaces.
# Usage: retab *.*
# See: https://stackoverflow.com/q/11094383/55075
retab() {
ex +'set ts=2' +'bufdo retab' -cxa $*
}
:retabmoże w ogóle nie działać , globowanie powłoki jest złym rozwiązaniem dla tego rodzaju rzeczy , twoje :spolecenie zastąpi dowolną liczbę tabulatorów 2 spacjami (które prawie nigdy nie chcę), rozpoczęcie ex po prostu uruchomienia :!expandprocesu jest głupie ...