Làm cách nào tôi có thể chuyển đổi các tab thành khoảng trắng trong mỗi tệp của một thư mục?


251

Làm cách nào tôi có thể chuyển đổi các tab thành khoảng trắng trong mỗi tệp của một thư mục (có thể đệ quy)?

Ngoài ra, có cách nào để thiết lập số lượng khoảng trống trên mỗi tab không?


Bạn muốn thay thế các tab trong tập tin hoặc tên tập tin?
cppcoder

3
prlà một tiện ích tuyệt vời cho việc này. Xem câu trả lời này .
codeforester

Câu trả lời:


69

Cảnh báo: Điều này sẽ phá vỡ repo của bạn.

Điều này sẽ làm hỏng các tệp nhị phân , bao gồm cả những tệp dưới svn, .git! Đọc các bình luận trước khi sử dụng!

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

Các tập tin ban đầu được lưu dưới dạng [filename].orig.

Thay thế '* .java' bằng kết thúc tệp của loại tệp bạn đang tìm kiếm. Bằng cách này bạn có thể ngăn ngừa tham nhũng ngẫu nhiên của các tệp nhị phân.

Nhược điểm:

  • Sẽ thay thế các tab ở mọi nơi trong một tập tin.
  • Sẽ mất nhiều thời gian nếu bạn có một kết xuất SQL 5GB trong thư mục này.

12
đối với không gian trực quan là sự pha trộn giữa các tab và không gian, phương pháp này cho phép mở rộng không chính xác.
pizza

7
Tôi cũng sẽ thêm một trình so khớp tệp như ví dụ chỉ cho các tệp .php tìm ./ -iname "* .php" -type f -exec sed -i 's / \ t / / g' {} \;
Daniel Luca CleanUnicorn

98
KHÔNG SỬ DỤNG SED! Nếu có một tab được nhúng trong một chuỗi, bạn có thể sẽ đọc mã của mình. Đây là những gì lệnh mở rộng có nghĩa là để xử lý. Sử dụng expand.
David W.

5
@DavidW. Tôi chỉ đơn giản là cập nhật lệnh này để chỉ thay thế các tab từ đầu dòng. find ./ -type f -exec sed -i 's/^\t/####/g' {} \;. Nhưng tôi đã không nhận ra lệnh mở rộng - rất hữu ích!
Martin Konecny

29
KHÔNG ĐƯỢC DÙNG! Câu trả lời này cũng vừa phá hỏng kho git cục bộ của tôi. Nếu bạn có tệp chứa các tab và khoảng trắng hỗn hợp, nó sẽ chèn các chuỗi của #. Thay vào đó, hãy sử dụng câu trả lời của Gene hoặc bình luận của Doge.
con rối

344

Thay thế đơn giản với sedlà được nhưng không phải là giải pháp tốt nhất có thể. Nếu có các khoảng trống "phụ" giữa các tab, chúng sẽ vẫn ở đó sau khi thay thế, do đó lề sẽ bị rách. Các tab được mở rộng ở giữa các dòng cũng sẽ không hoạt động chính xác. Thay vào đó bash, chúng ta có thể nói

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

để áp dụng expandcho mọi tệp Java trong cây thư mục hiện tại. Xóa / thay thế -nameđối số nếu bạn đang nhắm mục tiêu một số loại tệp khác. Là một trong những ý kiến ​​đề cập, hãy thật cẩn thận khi xóa -namehoặc sử dụng thẻ đại diện yếu. Bạn có thể dễ dàng lưu trữ kho lưu trữ và các tập tin ẩn khác mà không có ý định. Đây là lý do tại sao câu trả lời ban đầu bao gồm điều này:

Bạn nên luôn luôn tạo một bản sao dự phòng của cây trước khi thử một cái gì đó như thế này trong trường hợp có sự cố.


2
@JeffreyMartinez Câu hỏi tuyệt vời. gniourf_gniourf đã chỉnh sửa câu trả lời ban đầu của tôi vào ngày 11 tháng 11 và đưa ra những nhận xét chê bai về việc không biết cách sử dụng hợp lý {}. Có vẻ như anh ta không biết $0khi nào -cđược sử dụng. Sau đó, dimo414 đã thay đổi từ việc tôi sử dụng temp trong thư mục chuyển đổi sang /tmp, sẽ chậm hơn nhiều nếu /tmpở trên một điểm gắn kết khác. Thật không may, tôi không có sẵn hộp Linux để kiểm tra $0đề xuất của bạn . Nhưng tôi nghĩ bạn đúng.
Gene

1
@Gene, cảm ơn bạn đã làm rõ, nghe có vẻ như stackoverflow ổn rồi: p. Mặc dù tôi đang ở đó, tôi sẽ thêm tôi phải sử dụng các trích dẫn xung quanh '* .java' để thoát * .java đúng cách.
Jeffrey Martinez

2
Nếu bất kỳ ai đang gặp lỗi 'không biết chính hoặc toán tử' tìm thấy, thì đây là lệnh đầy đủ sẽ khắc phục:find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
Doge

4
Tôi nghĩ rằng câu trả lời này không có đủ ý kiến ​​như vậy, vì vậy đây là của tôi: nếu sử dụng spongetừ joeyh.name/code/moreutils , bạn có thể viếtfind . -name '*.py' ! -type d -exec bash -c 'expand -t 8 "$0" | sponge "$0"' {} \;
tokland

8
Đừng ngu ngốc và sử dụng find . -name '*', tôi vừa phá hủy repo git địa phương của tôi
Gautam

193

Hãy thử công cụ dòng lệnh expand.

expand -i -t 4 input | sponge output

Ở đâu

  • -i được sử dụng để chỉ mở rộng các tab hàng đầu trên mỗi dòng;
  • -t 4 có nghĩa là mỗi tab sẽ được chuyển đổi thành 4 ký tự khoảng trắng (8 theo mặc định).
  • spongelà từ moreutilsgói và tránh xóa tệp đầu vào .

Cuối cùng, bạn có thể sử dụng gexpandtrên OSX, sau khi cài đặt coreutilsvới Homebrew (brew install coreutils ).


5
Đó là một trong GNU_Core_Utilities
kev

32
Bạn nên vượt qua -iđể expandchỉ thay thế các tab hàng đầu trên mỗi dòng. Điều này giúp tránh việc thay thế các tab có thể là một phần của mã.
Câu hỏi của Quolonel

10
Làm thế nào về mỗi tệp duy nhất trong một thư mục đệ quy?
ahnbizcad

4
Mỗi lần tôi cố gắng sử dụng nó sẽ làm trống một số (thường là tất cả) các tập tin. : \
ThorSummoner

5
@ThorSummoner: if inputlà cùng một tệp với outputbash ghi đè nội dung trước khi bắt đầu expand. Đây là cách làm >việc.
Robert Siemer

34

Thu thập các ý kiến ​​tốt nhất từ câu trả lời của Gene , giải pháp tốt nhất cho đến nay, là bằng cách sử dụng spongetừ nhiều hơn .

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

Giải trình:

  • ./ đang tìm kiếm đệ quy từ thư mục hiện tại
  • -inamelà một trường hợp không nhạy cảm (cho cả hai *.java*.JAVAthích)
  • type -f chỉ tìm các tệp thông thường (không có thư mục, tệp nhị phân hoặc liên kết tượng trưng)
  • -exec bash -c thực hiện các lệnh sau trong một khung con cho mỗi tên tệp, {}
  • expand -t 4 mở rộng tất cả TAB thành 4 không gian
  • spongengâm đầu vào tiêu chuẩn (từ expand) và ghi vào một tệp (cùng một tệp) *.

LƯU Ý : * Chuyển hướng tệp đơn giản ( > "$0") sẽ không hoạt động ở đây vì nó sẽ ghi đè tệp quá sớm .

Ưu điểm : Tất cả các quyền của tệp gốc được giữ lại và không có tmptệp trung gian nào được sử dụng.


2
TIL: lệnh bọt biển tuyệt vời, sau 15 năm sử dụng Linux. Cảm ơn bạn hiệp sĩ bí ẩn từ internet.
sscarduzio

19

Sử dụng dấu gạch chéo-thoát sed.

Trên linux:

  • Thay thế tất cả các tab bằng 1 dấu gạch nối tại chỗ, trong tất cả các tệp * .txt:

    sed -i $'s/\t/-/g' *.txt
  • Thay thế tất cả các tab bằng 1 khoảng trắng tại chỗ, trong tất cả các tệp * .txt:

    sed -i $'s/\t/ /g' *.txt
  • Thay thế tất cả các tab bằng 4 khoảng trắng tại chỗ, trong tất cả các tệp * .txt:

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

Trên máy mac:

  • Thay thế tất cả các tab bằng 4 khoảng trắng tại chỗ, trong tất cả các tệp * .txt:

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

2
@ Машаsed -i '' $'s/\t/ /g' $(find . -name "*.txt")
xyzale

Câu trả lời này dường như là đơn giản nhất.
Yan King Yin

6

Bạn có thể sử dụng lệnh thường có sẵn pr(trang man ở đây ). Ví dụ: để chuyển đổi các tab thành bốn khoảng trắng, hãy làm điều này:

pr -t -e=4 file > file.expanded
  • -t đàn áp tiêu đề
  • -e=nummở rộng các tab vào numkhông gian

Để chuyển đổi tất cả các tệp trong cây thư mục theo cách đệ quy, trong khi bỏ qua các tệp nhị phân:

#!/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

Logic để bỏ qua các tệp nhị phân là từ bài viết này .

GHI CHÚ:

  1. Làm điều này có thể nguy hiểm trong repo git hoặc svn
  2. Đây không phải là giải pháp phù hợp nếu bạn có các tệp mã có các tab được nhúng trong chuỗi ký tự

1
Bất kỳ lợi thế expandnào cho rằng cả hai đều là POSIX? Ví dụ, nó có một tùy chọn thay đổi nội tuyến? An toàn Git tại: stackoverflow.com/a/52136507/895245
Ciro Santilli 冠状 病 六四 事件

5

Làm cách nào tôi có thể chuyển đổi các tab thành khoảng trắng trong mỗi tệp của một thư mục (có thể là đệ quy)?

Đây thường không phải là những gì bạn muốn.

Bạn có muốn làm điều này cho hình ảnh png? Tập tin PDF? Thư mục .git? Của bạn Makefile( yêu cầu các tab)? Kết xuất SQL 5GB?

Về lý thuyết, bạn có thể vượt qua rất nhiều tùy chọn loại trừ findhoặc bất cứ thứ gì bạn đang sử dụng; nhưng điều này rất dễ hỏng và sẽ bị hỏng ngay khi bạn thêm các tệp nhị phân khác.

Những gì bạn muốn, ít nhất là:

  1. Bỏ qua các tập tin trên một kích thước nhất định.
  2. Phát hiện nếu một tệp là nhị phân bằng cách kiểm tra sự hiện diện của byte NULL.
  3. Chỉ thay thế các tab khi bắt đầu một tệp ( expandthực hiện điều này, sed không).

Theo như tôi biết, không có tiện ích Unix "tiêu chuẩn" nào có thể làm được điều này và nó không dễ thực hiện với trình bao một lớp vỏ, vì vậy cần có một kịch bản.

Cách đây một thời gian, tôi đã tạo ra một đoạn script nhỏ gọi là sanitize_files , chính xác là nó. Nó cũng sửa một số nội dung phổ biến khác như thay thế \r\nbằng \n, thêm dấu \n, v.v.

Bạn có thể tìm thấy một tập lệnh được đơn giản hóa mà không có các tính năng bổ sung và các đối số dòng lệnh bên dưới, nhưng tôi khuyên bạn nên sử dụng tập lệnh trên vì nó có nhiều khả năng nhận được các lỗi và cập nhật khác hơn bài đăng này.

Tôi cũng muốn chỉ ra, để đáp lại một số câu trả lời khác ở đây, rằng sử dụng shell globalbing không phải là một cách mạnh mẽ để làm điều này, bởi vì sớm hay muộn bạn sẽ kết thúc với nhiều tệp hơn sẽ phù hợp ARG_MAX(trên hiện đại Các hệ thống Linux có giá 128 nghìn, có vẻ rất nhiều, nhưng sớm hay muộn thì không đủ).


#!/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)

Trong git, kiểm tra nhị phân rất dễ dàng: stackoverflow.com/a/52136507/895245
Ciro Santilli 冠状 病 事件

5

Tôi thích ví dụ "tìm" ở trên cho ứng dụng đệ quy. Để điều chỉnh nó thành không đệ quy, chỉ thay đổi các tệp trong thư mục hiện tại khớp với ký tự đại diện, việc mở rộng toàn cầu shell có thể đủ cho một lượng nhỏ tệp:

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

Nếu bạn muốn nó im lặng sau khi bạn tin tưởng rằng nó hoạt động, chỉ việc kéo thả -vvào shlệnh ở cuối.

Tất nhiên bạn có thể chọn bất kỳ tập hợp các tập tin trong lệnh đầu tiên. Ví dụ: chỉ liệt kê một thư mục con (hoặc thư mục) cụ thể theo cách được kiểm soát như sau:

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

Hoặc lần lượt chạy find (1) với một số kết hợp các tham số độ sâu, v.v .:

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

1
Shell globalbing sẽ phá vỡ sớm hay muộn, bởi vì tổng số lượng tên tệp chỉ có thể có ARG_MAXđộ dài. Đây là 128k trên các hệ thống Linux, nhưng tôi đã gặp phải giới hạn này đủ lần để không phụ thuộc vào toàn cầu.
Martin Tournoij

1
Bạn không thực sự cần phải thích nghi với chúng. findcó thể được nói -maxdepth 1, và nó chỉ xử lý các mục của thư mục đang được sửa đổi, không phải toàn bộ cây.
ShadowRanger

4

Tôi đã sử dụng astyleđể thụt lại tất cả mã C / C ++ của mình sau khi tìm thấy các tab và khoảng trắng hỗn hợp. Nó cũng có các tùy chọn để buộc một kiểu niềng răng cụ thể nếu bạn muốn.


4

Người ta có thể sử dụng vimcho điều đó:

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

Như Carpetsmoker đã nêu, nó sẽ thử lại theo vimcài đặt của bạn . Và modelines trong các tập tin, nếu có. Ngoài ra, nó sẽ thay thế các tab không chỉ ở đầu dòng. Đó không phải là những gì bạn thường muốn. Ví dụ, bạn có thể có chữ, chứa các tab.


:retabsẽ thay đổi tất cả các tab trong một tệp, không phải các tab khi bắt đầu. nó cũng phụ thuộc vào những gì :tabstop:expandtabcài đặt của bạn trong vimrc hoặc modeline, vì vậy điều này có thể không hoạt động.
Martin Tournoij

@Carpetsmoker Điểm hay về các tab ở đầu dòng. Có bất kỳ giải pháp ở đây xử lý trường hợp này? Đối với tabstopexpandtabcài đặt, nó sẽ hoạt động nếu bạn đang sử dụng vim. Trừ khi bạn có các dòng chế độ trong các tập tin.
x-yuri

@ x-yuri câu hỏi hay, nhưng nói chung là moot. Hầu hết mọi người sử dụng các tab không thực sự bằng chữ.
Ricardo Cruz

4

Đề nghị của tôi là sử dụng:

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

Bình luận:

  1. Sử dụng tại chỗ chỉnh sửa. Giữ các bản sao lưu trong một VCS. Không cần phải tạo tệp * .orig. Đó là cách thực hành tốt để phân biệt kết quả so với cam kết cuối cùng của bạn để đảm bảo rằng điều này hoạt động như mong đợi, trong mọi trường hợp.
  2. sedlà một biên tập viên dòng. Sử dụng exđể chỉnh sửa tại chỗ. Điều này tránh việc tạo thêm các tệp tạm thời và vỏ sinh sản cho mỗi lần thay thế như trong câu trả lời hàng đầu .
  3. CẢNH BÁO: Điều này gây rối với tất cả các tab, không chỉ những tab được sử dụng để thụt lề. Ngoài ra, nó không làm thay thế nhận thức ngữ cảnh của các tab. Điều này là đủ cho trường hợp sử dụng của tôi. Nhưng có thể không được chấp nhận cho bạn.
  4. EDIT: Một phiên bản trước của câu trả lời này được sử dụng find|xargsthay vì find -exec. Như được chỉ ra bởi @ gniourf-gniourf, điều này dẫn đến các vấn đề về khoảng trắng, dấu ngoặc kép và ký tự điều khiển trong tên tệp. Bánh xe .

excó thể không có sẵn trên mọi hệ thống Unix. Thay thế nó có vi -ethể hoạt động trên nhiều máy hơn. Ngoài ra, regex của bạn thay thế bất kỳ số lượng ký tự tab bắt đầu bằng hai khoảng trắng. Thay thế regex bằng +%s/\t/ /gkhông phá hủy thụt đa cấp. Tuy nhiên, điều này cũng ảnh hưởng đến các ký tự tab không được sử dụng để thụt lề.
Lukas Schmelzeisen

ex là một phần của POSIX [1] vì vậy nên có sẵn. Điểm tốt về sự đa cấp. Tôi thực sự đã sử dụng /\t/ /biến thể trên các tệp của mình, nhưng đã chọn /\t\+//không phá vỡ các tab không thụt lề. Bỏ lỡ các vấn đề với đa thụt! Cập nhật câu trả lời. [1] man7.org/linux/man-pages/man1/ex.1p.html#SEE%C2%A0ALSO
Heinrich Hartmann

2
Sử dụng xargstheo cách này là vô ích, không hiệu quả và bị hỏng (nghĩ về tên tệp chứa khoảng trắng hoặc dấu ngoặc kép). Tại sao bạn không sử dụng find's -execswitch để thay thế?
gniourf_gniourf

Tôi cho rằng tên tập tin có dấu cách và dấu ngoặc kép bị hỏng; ) Nếu bạn cần hỗ trợ mà tôi chọn: -print0các tùy chọn để tìm / xargs. Tôi thích xargs hơn -execvì: a) Tách các mối quan tâm b) nó có thể được hoán đổi với GNU song song dễ dàng hơn.
Heinrich Hartmann

Cập nhật thêm bình luận @gniourf_gniourf.
Heinrich Hartmann

4

Để chuyển đổi tất cả các tệp Java theo cách đệ quy trong một thư mục để sử dụng 4 khoảng trắng thay vì một tab:

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

Câu trả lời này khác với câu trả lời này được đăng 4 năm trước như thế nào?
PP

2
Câu trả lời của bạn cũng vậy. Trên thực tế, đây là phiên bản kém hơn trong câu trả lời của Gene: 1) Câu trả lời của Gene chăm sóc các thư mục có cùng tên. 2) Nó không di chuyển nếu mở rộng thất bại.
PP

4

Bạn có thể sử dụng findvới tabs-to-spacesgói cho việc này.

Đầu tiên, cài đặt tabs-to-spaces

npm install -g tabs-to-spaces

sau đó, chạy lệnh này từ thư mục gốc của dự án của bạn;

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

Điều này sẽ thay thế mỗi tabký tự bằng 2 spacestrong mỗi tệp.


3

Không có cơ thể đề cập rpl? Sử dụng rpl bạn có thể thay thế bất kỳ chuỗi. Để chuyển đổi các tab thành không gian,

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

rất đơn giản.


1
Điều này làm hỏng tất cả các tệp nhị phân trong repo của tôi.
Aaron Franke

1
Một lệnh tuyệt vời, nhưng có khả năng nguy hiểm với đệ quy và tất cả các tệp trong tùy chọn thư mục như được chỉ định ở trên. Tôi sẽ thêm tùy chọn --dry-run "chỉ trong trường hợp" để đảm bảo bạn đang ngồi đúng thư mục.
MortimerCat

2

Việc sử dụng expandnhư được đề xuất trong các câu trả lời khác có vẻ là cách tiếp cận hợp lý nhất cho nhiệm vụ này.

Điều đó nói rằng, nó cũng có thể được thực hiện với Bash và Awk trong trường hợp bạn có thể muốn thực hiện một số sửa đổi khác cùng với nó.

Nếu sử dụng Bash 4.0 trở lên, có thể sử dụng nội dung shopt globstar để tìm kiếm đệ quy với **.

Với GNU Awk phiên bản 4.1 trở lên, có thể thực hiện các sửa đổi tệp "inplace" sed:

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

Trong trường hợp bạn muốn đặt số lượng khoảng trống trên mỗi tab:

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

2

Tải xuống và chạy tập lệnh sau để chuyển đổi đệ quy các tab cứng thành các tab mềm trong các tệp văn bản thuần túy.

Thực thi tập lệnh từ bên trong thư mục chứa các tệp văn bản thuần túy.

#!/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;

2

Phương pháp thân thiện với kho 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"
)

Hành động trên tất cả các tệp trong thư mục hiện tại:

git-tab-to-space

Chỉ hành động trên các tệp C hoặc C ++:

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

Bạn có thể muốn điều này đáng chú ý vì những Makefiles phiền phức đòi hỏi các tab.

Lệnh git grep --cached -Il '':

  • chỉ liệt kê các tệp được theo dõi, vì vậy không có gì bên trong .git
  • loại trừ các thư mục, tệp nhị phân (sẽ bị hỏng) và liên kết tượng trưng (sẽ được chuyển đổi thành tệp thông thường)

như đã giải thích tại: Làm thế nào để liệt kê tất cả các tệp văn bản (không phải nhị phân) trong kho git?

chmod --referencegiữ quyền truy cập tệp không thay đổi: /unix/20645/clone-ownership-and-permissions-from-another-file Thật không may tôi không thể tìm thấy giải pháp thay thế POSIX ngắn gọn .

Nếu cơ sở mã của bạn có ý tưởng điên rồ là cho phép các tab thô chức năng trong chuỗi, hãy sử dụng:

expand -i

và sau đó vui vẻ đi qua tất cả các tab không bắt đầu từng cái một, mà bạn có thể liệt kê với: Có thể git grep cho các tab không?

Đã thử nghiệm trên Ubuntu 18.04.


-1

Chuyển đổi các tab thành không gian chỉ trong các tệp ".lua" [tab -> 2 dấu cách]

find . -iname "*.lua" -exec sed -i "s#\t#  #g" '{}' \;

Rõ ràng, lượng không gian mà một tab mở rộng phụ thuộc vào ngữ cảnh. Vì vậy, sed là một công cụ hoàn toàn không phù hợp cho nhiệm vụ.
Sven

?? @Sven, lệnh sed của tôi thực hiện điều tương tự như lệnh mở rộng ( expand -t 4 input >output)
Makah

3
Dĩ nhiên là không. expand -t 4sẽ mở rộng tab a\tbthành 3 khoảng trắng và tab aa\tbthành 2 khoảng trắng, giống như cần thiết. expandđưa ngữ cảnh của một tab vào tài khoản, sedkhông và sẽ thay thế tab bằng lượng không gian bạn chỉ định, bất kể bối cảnh.
Sven

-1

Sử dụng vim-way:

$ ex +'bufdo retab' -cxa **/*.*
  • Tạo bản sao lưu! trước khi thực hiện lệnh trên, vì nó có thể làm hỏng các tệp nhị phân của bạn.
  • Để sử dụng globstar( **) cho đệ quy, kích hoạt bằng shopt -s globstar.
  • Để chỉ định loại tệp cụ thể, sử dụng ví dụ : **/*.c.

Để sửa đổi tabstop, thêm +'set ts=2'.

Tuy nhiên, mặt trái là nó có thể thay thế các tab bên trong chuỗi .

Vì vậy, để có giải pháp tốt hơn một chút (bằng cách sử dụng thay thế), hãy thử:

$ ex -s +'bufdo %s/^\t\+/  /ge' -cxa **/*.*

Hoặc bằng cách sử dụng extrình chỉnh sửa + expandtiện ích:

$ ex -s +'bufdo!%!expand -t2' -cxa **/*.*

Đối với dấu cách, hãy xem: Làm cách nào để xóa khoảng trắng ở cuối cho nhiều tệp?


Bạn có thể thêm chức năng sau vào .bash_profile:

# Convert tabs to spaces.
# Usage: retab *.*
# See: https://stackoverflow.com/q/11094383/55075
retab() {
  ex +'set ts=2' +'bufdo retab' -cxa $*
}

Tôi đã đánh giá thấp nhiều câu trả lời trong chủ đề này, không chỉ của bạn ;-) Lý do là: :retabcó thể không hoạt động , shell globalbing là một giải pháp tồi cho loại điều này , :slệnh của bạn sẽ thay thế bất kỳ số lượng tab nào bằng 2 khoảng trắng (mà bạn gần như không bao giờ muốn), bắt đầu ex chỉ để chạy một :!expandquá trình là ngớ ngẩn ...
Martin Tournoij

... và tất cả các giải pháp của bạn sẽ ghi đè các tệp nhị phân và như vậy (như tệp .png, tệp .pdf, v.v.)
Martin Tournoij

Đây thực sự là một gợi ý khủng khiếp cho tài liệu - người ta phải làm quen với một số cú pháp khá mờ và các vấn đề ngữ nghĩa của một số chương trình để có thể hiểu điều này.
Josip Rodin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.