Chuyển đổi tab thành không gian trong nhiều tệp


11

Tôi có rất nhiều tệp với các tab rải rác khắp nơi và tôi muốn chuyển đổi tất cả chúng thành không gian. Tôi biết về expandlệnh này, nhưng thật không may, tôi sẽ phải gõ từng tệp bằng cách sử dụng nó. Có cách nào dễ dàng hơn để làm điều này trên Linux không?

Câu trả lời:


12

Hãy thử như sau:

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

Nếu bạn muốn bốn không gian, hãy thử:

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

Điều đó sẽ thay thế mỗi tab bằng một không gian duy nhất. Vì người được đề cập sử dụng expand, tôi cho rằng họ muốn sự liên kết của văn bản được bảo tồn.
garyjohn

Bạn cần phải 's/\t/ /g'thay thế nhiều hơn một tab trên mỗi dòng.
Daniel Andersson

1
Tăng tốc đáng kể nếu có nhiều tệp đang thực hiện " find ./ -type f -exec sed -i ’s/\t/ /g’ {} +" (nghĩa là " +" thay vì " \;"), nếu findphiên bản hỗ trợ (và cá nhân tôi chưa gặp bất kỳ phiên bản nào không có, nhưng đó không phải là tiêu chuẩn POSIX , vì vậy tôi đoán nó có thể xảy ra trên một số hệ thống. Xem " -exec command {} +" trong hướng dẫn). Thay vì khởi chạy một phiên bản sedcho mỗi tệp, điều này sẽ xây dựng một danh sách đối số có nhiều đối số tên tệp mà hệ thống hỗ trợ ( getconf ARG_MAX= 2097152 trên hệ thống của tôi), giống như xargs, và do đó khởi chạy ít sedquy trình hơn .
Daniel Andersson

6
Lưu ý đối với bất kỳ người dùng Mac nào tìm thấy điều này: Phiên bản của OS X sedkhông hiểu \ttrình tự thoát tab. Bạn có thể thay thế nó bằng một ký tự tab theo nghĩa đen mà bạn có thể nhập vào trình bao [Ctrl]+V, [Tab].
Jeremy Banks

expandcó lẽ tốt hơn sedcho điều này, như được giải thích trong: stackoverflow.com/a/11094620/131824
David Weinraub

6

Có rất nhiều cách để làm điều này. Cũng có rất nhiều cách để bạn tự bắn vào chân mình trong khi thực hiện việc này nếu bạn không cẩn thận hoặc nếu bạn chưa quen với Linux như bạn có vẻ. Giả sử rằng bạn có thể tạo một danh sách các tệp mà bạn muốn chuyển đổi, bằng cách sử dụng một cái gì đó giống findhoặc bằng tay với một trình soạn thảo, chỉ cần đưa danh sách đó vào danh sách sau đây.

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

Một cách bạn có thể tự bắn vào chân mình là tạo một lỗi đánh máy để bạn kết thúc một tập tin trống cho tất cả các tên tập tin bạn chỉ định, từ đó xóa nội dung của tất cả các tập tin của bạn. Vì vậy, hãy cẩn thận và kiểm tra bất cứ điều gì bạn làm đầu tiên trên một tập hợp nhỏ các tập tin mà bạn đã sao lưu.


3
Làm cho mvđiều kiện về sự thành công của expand:expand ... && mv ...
Tạm dừng cho đến khi có thông báo mới.

Đừng quên expand -t 4mở rộng các tab thành 4 không gian. Ngoài ra, phương pháp này có thể tạo ra các dòng mới. Nhưng nếu không nó hoạt động.
mgold

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

-I foo tạo một biến mẫu foo cho mỗi dòng đầu vào, do đó bạn có thể tham khảo đầu vào nhiều lần.

-print0-0báo cho cả hai lệnh sử dụng \ 0 làm dấu tách dòng thay vì SPACE, vì vậy lệnh này hoạt động cho các đường dẫn có khoảng trắng.


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

Nhược điểm:
các tệp lớn hơn kích thước bộ đệm ống ( 64KB ) bị cắt ngắn

Ưu điểm:
không có tệp tệp tạm thời nào
lớn hơn kích thước bộ đệm ống bị cắt ngắn


0

Thế này tốt hơn:

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

3
Tại sao điều này tốt hơn? Nó không phải là một ý tưởng tuyệt vời để sử dụng /tmp/ebởi vì nếu có bất cứ điều gì khác đang sử dụng tập tin đó, điều này sẽ làm rối tung nó. Giống như nếu hai người dùng muốn sử dụng điều này cùng một lúc.
Kevin Panko

0

Tôi đã đưa ra vấn đề này với một yêu cầu sau đây:

  • Lọc các tệp dựa trên tên của chúng, để xử lý ví dụ chỉ tệp .cpp hoặc .json
  • Hỗ trợ xử lý song song. Trong trường hợp có nhiều tệp, điều này có thể cung cấp một tốc độ rất lớn
  • Các giải pháp nên phù hợp trong một dòng để dễ sử dụng

Yêu cầu cuối cùng là khó thực hiện nhất vì "mở rộng" không cho phép sửa đổi các tệp tại chỗ.

Tôi đã đưa ra giải pháp sau đây:

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'

Đây là một số giải thích:

  • "tìm" tìm các tập tin để xử lý. "-regextype egrep" cho phép lọc chúng dựa trên tên của chúng và một biểu thức chính quy ở định dạng "egrep"
  • tham số "-type f" đảm bảo rằng chúng tôi sẽ chỉ khớp các tệp thông thường, không phải cho các thư mục ví dụ hoặc bất kỳ thứ gì đặc biệt
  • tham số "-regrec" là chính biểu thức chính, khớp với trường hợp này bất kỳ tệp nào kết thúc bằng .c, .cpp, .h hoặc .hpp (toàn bộ tên phải khớp, vì vậy "file.c2" sẽ không , đó là những gì chúng ta muốn)
  • "-print0" hướng dẫn "tìm" để in các đường dẫn tệp trên đầu ra tiêu chuẩn của nó với ký tự 0 ở cuối mỗi đường dẫn. Cùng với tùy chọn "-0" cho "xargs", nó cho phép chuyển các tên có chứa các đường quay trở lại từ công cụ này sang công cụ khác (ngay cả khi đó là một tình huống khá hiếm gặp ...)
  • xargs bắt đầu một quy trình mới cho mỗi đường dẫn ("-n 1"), nhưng có thể chạy song song 10 tiến trình ("-P 10")
  • xargs sử dụng bí danh "FILE" để truyền từng đường dẫn tệp cho lệnh, đó là một tập lệnh bash
  • tập lệnh bash gọi "bung rộng" và lưu kết quả vào một tệp tạm thời có tên chứa ID tiến trình hiện tại ($$), để tất cả các quy trình chạy song song tại một tệp nhất định sử dụng các tệp tạm thời khác nhau
  • toàn bộ lệnh sử dụng mẫu (lệnh1 && lệnh2 && lệnh3) để quá trình sẽ dừng lại nếu bất kỳ tiểu ban nào trả về lỗi
  • nếu có bất kỳ lỗi nào từ chuỗi "&&" trước đó, tập lệnh bash sẽ trả về mã thoát 255 sẽ khiến xargs dừng ngay lập tức
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.