Konwertowanie tabulatorów na spacje w wielu plikach


11

Mam dużo plików z kartami pełnymi w środku i chciałbym przekonwertować je wszystkie w spacje. Wiem o tym expandpoleceniu, ale niestety musiałbym wpisać każdy pojedynczy plik, używając go. Czy jest na to łatwiejszy sposób w Linuksie?

Odpowiedzi:


12

Spróbuj wykonać następujące czynności:

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

Jeśli chcesz cztery spacje, spróbuj:

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

To zastąpi każdą kartę pojedynczym odstępem. Ponieważ osoba wspomniała o użyciu expand, zakładam, że chce zachować wyrównanie tekstu.
garyjohn

Musisz 's/\t/ /g'zastąpić więcej niż jedną kartę w wierszu.
Daniel Andersson

1
Znaczne przyspieszenie, jeśli jest wiele plików, powoduje „ find ./ -type f -exec sed -i ’s/\t/ /g’ {} +” (to znaczy „ +” zamiast „ \;”), jeśli findwersja je obsługuje (a ja osobiście nie spotkałem żadnej wersji, która tego nie robi, ale nie jest to standard POSIX , więc myślę, że może się to zdarzyć na niektórych systemach. Patrz „ -exec command {} +” w instrukcji). Zamiast uruchamiać jedną instancję seddla każdego pliku, utworzy to listę argumentów z tyloma argumentami nazwy pliku, ile obsługuje system ( getconf ARG_MAX= 2097152 w moim systemie), podobnie jak xargs, i tym samym uruchamia znacznie mniej sedprocesów.
Daniel Andersson

6
Uwaga dla wszystkich użytkowników komputerów Mac, którzy znajdą to: Wersja OS X sednie rozumie \tsekwencji znaków zmiany znaczenia. Możesz go zastąpić dosłownym znakiem tabulacji, który możesz wprowadzić w powłoce [Ctrl]+V, [Tab].
Jeremy Banks,

expandjest prawdopodobnie lepszy niż seddo tego, jak wyjaśniono w: stackoverflow.com/a/11094620/131824
David Weinraub

6

Jest na to wiele sposobów. Istnieje również wiele sposobów, aby strzelić sobie w stopę, robiąc to, jeśli nie jesteś ostrożny lub jesteś nowy w Linuksie, jak się wydaje. Zakładając, że możesz utworzyć listę plików, które chcesz przekonwertować, albo używając czegoś podobnego findlub ręcznie w edytorze, po prostu potokuj tę listę w następujący sposób.

while read file
do
   expand "$file" > /tmp/expandtmp
   mv /tmp/expandtmp "$file"
done

Jednym ze sposobów, w jaki możesz strzelić sobie w stopę, jest napisanie literówki, aby skończyć na pustym pliku dla wszystkich podanych nazw plików, usuwając w ten sposób zawartość wszystkich plików. Bądź więc ostrożny i przetestuj wszystko, co robisz najpierw, na małym zestawie plików, których kopię zapasową utworzono.


3
Uzależnij mvod powodzenia expand:expand ... && mv ...
Wstrzymano do odwołania.

Nie zapomnij expand -t 4rozwinąć tabulatorów do 4 spacji. Ponadto ta metoda może tworzyć końcowe znaki nowej linii. Ale poza tym to działa.
mgold

3
find . -type f -iname "*.js" -print0 | xargs -0 -I foo tab2space foo foo

-I foo tworzy szablonową zmienną foo dla każdej linii wejściowej, dzięki czemu można odwoływać się do danych wejściowych więcej niż jeden raz.

-print0i -0każ obu komendom używać \ 0 jako separatora linii zamiast SPACJI, więc to polecenie działa dla ścieżek ze spacjami.


1
find -name \*.js -exec bash -c 'expand -t 4 "$0" | tee "$0"' {} \;

Wady:
pliki większe niż rozmiar bufora potoku ( 64 KB ) zostają obcięte

Plusy:
żadne pliki tymczasowe
większe niż rozmiar bufora potoku nie są obcinane


0

To jest lepsze:

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

3
Dlaczego to jest lepsze? Nie jest to świetny pomysł, /tmp/eponieważ jeśli coś innego korzysta z tego pliku, to go zepsuje. Jak gdyby dwóch użytkowników chciało z tego korzystać jednocześnie.
Kevin Panko

0

Dałem temu problemowi uwagę, mając na uwadze następujące wymagania:

  • Filtruj pliki według ich nazw, aby przetworzyć na przykład tylko plik .cpp lub .json
  • Obsługuje przetwarzanie równoległe. W przypadku wielu plików może to znacznie przyspieszyć
  • Rozwiązanie powinno pasować do jednej linii, aby było łatwe w użyciu

Ostatni wymóg był najtrudniejszy do spełnienia, ponieważ „rozwijanie” nie pozwala modyfikować plików w miejscu.

Wymyśliłem następujące rozwiązanie:

find . -type f -regextype egrep -regex '.*\.(c|cpp|h|hpp)'  -print0 | xargs -0 -n 1 -P 10 -IFILE bash -c ' ( echo "Processing FILE..." && expand -t 4 "FILE" > /tmp/expand.$$ && mv /tmp/expand.$$ "FILE" ) || exit 255'

Oto kilka wyjaśnień:

  • „znajdź” wyszukuje pliki do przetworzenia. „-regextype egrep” pozwala filtrować je na podstawie ich nazwy i wyrażenia regularnego w formacie „egrep”
  • parametr „-type f” zapewnia, że ​​dopasujemy tylko zwykłe pliki, a nie na przykład katalogi lub cokolwiek innego specjalnego
  • parametr „-regexp” jest samym wyrażeniem regularnym, które w tym przypadku pasuje do każdego pliku, który kończy się na .c, .cpp, .h lub .hpp (cała nazwa musi się zgadzać, więc „file.c2” nie , czego chcemy)
  • „-print0” instruuje „find”, aby wydrukował ścieżki plików na standardowym wyjściu ze znakiem 0 na końcu każdej ścieżki. Wraz z opcją „-0” dla „xargs” pozwala na przekazywanie nazw zawierających powozy z jednego narzędzia do drugiego (nawet jeśli jest to dość rzadka sytuacja ...)
  • xargs uruchamia nowy proces dla każdej ścieżki („-n 1”), ale może uruchomić nawet 10 procesów równolegle („-P 10”)
  • xargs używa aliasu „PLIK” do przekazania każdej ścieżki pliku do polecenia, które jest skryptem bash
  • skrypt bash wywołuje „rozwiń” i zapisuje wynik w pliku tymczasowym, którego nazwa zawiera bieżący identyfikator procesu ($$), dzięki czemu wszystkie procesy działające równolegle w danym pliku używają różnych plików tymczasowych
  • całe polecenie używa wzorca (polecenie1 i& polecenie2 i& polecenie3), aby proces został zatrzymany, jeśli jakakolwiek komenda zwróci błąd
  • jeśli wystąpi błąd z poprzedniego łańcucha „&&”, skrypt bash zwróci kod wyjścia 255, który spowoduje natychmiastowe zatrzymanie xargs
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.