ฉันจะแปลงแท็บเป็นช่องว่างในทุกไฟล์ของไดเรกทอรีได้อย่างไร


251

ฉันจะแปลงแท็บเป็นช่องว่างในทุกไฟล์ของไดเรกทอรี (อาจเรียกซ้ำ)

นอกจากนี้ยังมีวิธีตั้งค่าจำนวนช่องว่างต่อแท็บหรือไม่


คุณต้องการแทนที่แท็บในไฟล์หรือชื่อไฟล์?
cppcoder

3
prเป็นเครื่องมือที่ยอดเยี่ยมสำหรับสิ่งนี้ ดูคำตอบนี้
codeforester

คำตอบ:


69

คำเตือน: นี่จะทำลาย repo ของคุณ

นี้จะไฟล์ไบนารีเสียหายรวมทั้งภายใต้เหล่านั้นsvn, .git! อ่านความคิดเห็นก่อนใช้!

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

[filename].origไฟล์ต้นฉบับจะถูกบันทึกเป็น

แทนที่ '* .java' ด้วยไฟล์ที่ลงท้ายด้วยประเภทไฟล์ที่คุณต้องการ วิธีนี้คุณสามารถป้องกันความเสียหายของไฟล์ไบนารีโดยไม่ตั้งใจ

ข้อเสีย:

  • จะแทนที่แท็บทุกที่ในไฟล์
  • จะใช้เวลานานถ้าคุณมีการถ่ายโอนข้อมูล SQL 5GB ในไดเรกทอรีนี้

12
สำหรับพื้นที่ภาพที่มีแท็บและช่องว่างผสมผสานกันวิธีการนี้ทำให้เกิดการขยายที่ไม่ถูกต้อง
พิซซ่า

7
ฉันจะเพิ่มตัวจับคู่ไฟล์เช่นสำหรับไฟล์. php เท่านั้นที่พบ. / -iname "* .php" -type f -exec sed -i 's / \ t / / g' {} \;
Daniel Luca CleanUnicorn

98
ห้ามใช้ SED! หากมีแท็บฝังตัวอยู่ในสตริงคุณอาจสิ้นสุดรหัสของคุณ นี่คือสิ่งที่คำสั่งขยายเพื่อจัดการ expandใช้
David W.

5
@DavidW ฉันเพียงแค่อัปเดตคำสั่งนี้เพื่อแทนที่แท็บจากจุดเริ่มต้นของบรรทัด find ./ -type f -exec sed -i 's/^\t/####/g' {} \;. แต่ฉันไม่ได้ตระหนักถึงคำสั่งขยาย - มีประโยชน์มาก!
Martin Konecny

29
ไม่ได้ใช้! คำตอบนี้ก็ทำลายที่เก็บ git ในพื้นที่ของฉัน หากคุณมีไฟล์ที่มีแท็บผสมและช่องว่างมันจะแทรกลำดับของ # ใช้คำตอบโดย Gene หรือความคิดเห็นของ Doge ด้านล่างแทน
หุ่น

344

การเปลี่ยนที่เรียบง่ายด้วยsedก็โอเค แต่ไม่ใช่ทางออกที่ดีที่สุด หากมีช่องว่าง "พิเศษ" ระหว่างแท็บพวกเขาจะยังคงอยู่ที่นั่นหลังจากการทดแทนดังนั้นระยะขอบจะถูกขาด แท็บที่ขยายตรงกลางบรรทัดจะทำงานไม่ถูกต้อง ในbashเราสามารถพูดแทน

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

เพื่อใช้expandกับทุกไฟล์ Java ในแผนผังไดเร็กทอรีปัจจุบัน ลบ / แทนที่-nameอาร์กิวเมนต์หากคุณกำหนดเป้าหมายไฟล์ประเภทอื่น ในฐานะที่เป็นหนึ่งในความคิดเห็นที่กล่าวถึงโปรดใช้ความระมัดระวังเมื่อลบ-nameหรือใช้อักขระตัวแทนที่อ่อนแอ คุณสามารถอุดตันพื้นที่เก็บข้อมูลและไฟล์ที่ซ่อนอื่น ๆ ได้โดยไม่ต้องตั้งใจ นี่คือเหตุผลที่คำตอบเดิมรวมอยู่ในนี้:

คุณควรทำสำเนาสำรองต้นไม้ก่อนที่จะลองทำสิ่งนี้ในกรณีที่มีสิ่งผิดปกติ


2
@JeffreyMartinez เป็นคำถามที่ดีมาก gniourf_gniourf แก้ไขคำตอบเดิมของฉันเมื่อวันที่ 11 พฤศจิกายนและพูดจาดูถูกเหยียดหยามว่าไม่รู้วิธีการใช้ที่{}เหมาะสม ดูเหมือนว่าเขาไม่รู้ว่าใช้$0เมื่อ-cใด จากนั้น dimo414 เปลี่ยนจากการใช้ temp ในไดเรกทอรีการแปลงเป็น/tmpซึ่งจะช้ากว่ามากหาก/tmpอยู่ในจุดเมานท์อื่น น่าเสียดายที่ฉันไม่มีกล่อง Linux เพื่อทดสอบ$0ข้อเสนอของคุณ แต่ฉันคิดว่าคุณถูกต้อง
ยีน

1
@ ยีนขอบคุณสำหรับการชี้แจงที่ดูเหมือนว่า stackoverflow เอาล่ะ: p ในขณะที่ฉันอยู่ที่มันฉันจะเพิ่มฉันต้องใช้เครื่องหมายคำพูดรอบ '* .java' เพื่อการหลบหนีที่เหมาะสมของ * .java
Jeffrey Martinez

2
ถ้าใครจะมี 'ไม่รู้จักหลักหรือผู้ประกอบการ' ข้อผิดพลาดจากการค้นพบแล้วที่นี่เป็นคำสั่งเต็มซึ่งจะแก้ไขได้:find . -name '*.java' ! -type d -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;
Doge

4
ฉันคิดว่าคำตอบนี้มีความคิดเห็นไม่เพียงพอเหมือนเดิมดังนั้นนี่คือของฉัน: ถ้าใช้งานspongeจากjoeyh.name/code/moreutilsคุณสามารถเขียนfind . -name '*.py' ! -type d -exec bash -c 'expand -t 8 "$0" | sponge "$0"' {} \;
tokland

8
อย่าโง่และใช้find . -name '*'ฉันเพิ่งทำลาย repo คอมไพล์ท้องถิ่นของฉัน
Gautam

193

expandลองใช้เครื่องมือบรรทัดคำสั่ง

expand -i -t 4 input | sponge output

ที่ไหน

  • -i ใช้เพื่อขยายแท็บนำหน้าเท่านั้นในแต่ละบรรทัด
  • -t 4 หมายความว่าแต่ละแท็บจะถูกแปลงเป็น 4 ช่องว่าง (8 โดยค่าเริ่มต้น)
  • spongeอยู่ห่างจากmoreutilsแพคเกจและหลีกเลี่ยงการล้างแฟ้มใส่

ในที่สุดคุณสามารถใช้gexpandบน OSX หลังจากติดตั้งcoreutilsด้วย Homebrew ( brew install coreutils)


5
มันเป็นหนึ่งในGNU_Core_Utilities
kev

32
คุณควรส่ง-iต่อไปexpandยังแทนที่แท็บนำในแต่ละบรรทัดเท่านั้น สิ่งนี้จะช่วยหลีกเลี่ยงการแทนที่แท็บที่อาจเป็นส่วนหนึ่งของรหัส
คำถาม Quolonel

10
วิธีการเกี่ยวกับทุก ๆ ไฟล์ในไดเรกทอรีซ้ำ?
ahnbizcad

4
ทุกครั้งที่ฉันพยายามใช้สิ่งนี้มันจะว่างเปล่าบางส่วน (โดยปกติทั้งหมด) ของไฟล์ : \
ThorSummoner

5
@ThorSummoner: ถ้าinputเป็นไฟล์เดียวกับoutputclobbers expandทุบตีเนื้อหาก่อนที่จะได้เริ่มต้น นี่คือวิธีการ>ทำงาน
Robert Siemer

34

การเก็บรวบรวมความคิดเห็นที่ดีที่สุดจากคำตอบของยีนทางออกที่ดีที่สุดโดยไกลคือการใช้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 ค้นหาไฟล์ปกติเท่านั้น (ไม่มีไดเรกทอรีไบนารีหรือ symlink)
  • -exec bash -c ดำเนินการคำสั่งต่อไปนี้ใน subshell สำหรับแต่ละชื่อไฟล์ {}
  • expand -t 4 ขยาย TAB ทั้งหมดเป็น 4 ช่องว่าง
  • spongeดื่มด่ำกับอินพุตมาตรฐาน (จากexpand) และเขียนไปยังไฟล์ (อันเดียวกัน) *

หมายเหตุ : * การเปลี่ยนเส้นทางแฟ้มอย่างง่าย ( > "$0") จะไม่ทำงานที่นี่เพราะมันจะเขียนทับไฟล์เร็วเกินไป

ข้อได้เปรียบ : การอนุญาตไฟล์ต้นฉบับทั้งหมดจะถูกเก็บไว้และไม่มีการใช้tmpไฟล์ระดับกลาง


2
TIL: คำสั่งฟองน้ำที่ยอดเยี่ยมหลังจาก 15 ปีของการใช้ Linux ขอบคุณอัศวินลึกลับจากอินเทอร์เน็ต
sscarduzio

19

sedใช้เครื่องหมายทับขวาหนี

บน linux:

  • แทนที่แท็บทั้งหมดด้วย 1 เครื่องหมายขีดคั่นแทนในไฟล์ * .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

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

คำตอบนี้ดูเหมือนจะง่ายที่สุด
Yan King Yin

6

คุณสามารถใช้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

ตรรกะสำหรับการข้ามไฟล์ไบนารีจากโพสต์นี้

บันทึก:

  1. การทำเช่นนี้อาจเป็นอันตรายใน git หรือ svn repo
  2. นี่ไม่ใช่ทางออกที่ถูกต้องหากคุณมีไฟล์โค้ดที่มีแท็บฝังอยู่ในตัวอักษรสตริง

1
มีข้อได้เปรียบexpandอะไรบ้างเนื่องจากทั้งสองเป็น POSIX? เช่นมีตัวเลือกการเปลี่ยนแปลงแบบอินไลน์หรือไม่ Git safety ที่: stackoverflow.com/a/52136507/895245
Ciro Santilli 法轮功冠状病病冠状事件法轮功

5

ฉันจะแปลงแท็บเป็นช่องว่างในทุกไฟล์ของไดเรกทอรี (อาจเรียกซ้ำ)

นี่ไม่ใช่สิ่งที่คุณต้องการ

คุณต้องการทำสิ่งนี้สำหรับภาพ png หรือไม่? ไฟล์ PDF? ไดเรกทอรี. git ของคุณ Makefile(ซึ่งต้องใช้แท็บ) การถ่ายโอนข้อมูล SQL 5GB หรือไม่

ในทางทฤษฎีคุณสามารถส่งผ่านตัวเลือกทั้งหมดจำนวนมากไปยังfindหรืออะไรก็ตามที่คุณกำลังใช้อยู่ แต่มันเปราะบางและจะแตกทันทีที่คุณเพิ่มไฟล์ไบนารีอื่น ๆ

สิ่งที่คุณต้องการอย่างน้อยก็:

  1. ข้ามไฟล์ในขนาดที่กำหนด
  2. ตรวจสอบว่าไฟล์เป็นไบนารีโดยตรวจสอบว่ามี NULL ไบต์หรือไม่
  3. แทนที่แท็บที่จุดเริ่มต้นของไฟล์เท่านั้น ( expandทำเช่นนี้sed ไม่ใช่)

เท่าที่ฉันรู้ไม่มียูทิลิตี้ Unix "มาตรฐาน" ที่สามารถทำสิ่งนี้ได้และมันไม่ง่ายเลยที่จะใช้ shell one-liner ดังนั้นจึงจำเป็นต้องใช้สคริปต์

เมื่อไม่นานมานี้ฉันได้สร้างสคริปต์เล็ก ๆ ชื่อว่า sanitize_filesซึ่งทำสิ่งนั้น นอกจากนี้ยังแก้ไขสิ่งทั่วไปอื่น ๆ เช่นแทนที่\r\nด้วย\nการเพิ่มส่วนท้าย\nฯลฯ

คุณสามารถค้นหาสคริปต์ที่ง่ายขึ้นโดยไม่มีคุณสมบัติพิเศษและอาร์กิวเมนต์บรรทัดคำสั่งด้านล่าง แต่ฉันขอแนะนำให้คุณใช้สคริปต์ข้างต้นเนื่องจากมีแนวโน้มที่จะได้รับการแก้ไขข้อบกพร่องและการอัปเดตอื่น ๆ กว่าโพสต์นี้

ฉันอยากจะชี้ให้เห็นในการตอบสนองต่อคำตอบอื่น ๆ ที่นี่ว่าการใช้ shell globbing ไม่ใช่วิธีที่มีประสิทธิภาพในการทำเช่นนี้เพราะไม่ช้าก็เร็วคุณจะพบไฟล์จำนวนมากเกินกว่าจะเหมาะกับARG_MAX(ในปัจจุบัน ระบบลินุกซ์มันเป็น 128k ซึ่งอาจดูเหมือนมาก แต่ไม่ช้าก็เร็วมันก็ไม่ เพียงพอ)


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

ภายในระบบคอมไพล์การตรวจสอบแบบไบนารีนั้นง่าย: stackoverflow.com/a/52136507/895245
Ciro Santilli 郝海东冠状冠状病六四事件事件

5

ฉันชอบตัวอย่าง "ค้นหา" ด้านบนสำหรับแอปพลิเคชันแบบเรียกซ้ำ หากต้องการปรับให้เป็นแบบไม่เรียกซ้ำเฉพาะการเปลี่ยนไฟล์ในไดเรกทอรีปัจจุบันที่ตรงกับสัญลักษณ์ตัวแทนการขยายเชลล์ glob นั้นเพียงพอสำหรับไฟล์จำนวนน้อย:

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

1
Shell globbing จะแตกหักไม่ช้าก็เร็วเพราะชื่อไฟล์ทั้งหมดมีARG_MAXความยาวได้เท่านั้น นี่คือ 128k บนระบบ Linux แต่ฉันได้พบกับข้อ จำกัด นี้เวลาเพียงพอที่จะไม่พึ่งพาเชลล์ globbing
Martin Tournoij

1
คุณไม่จำเป็นต้องปรับมัน findสามารถบอก-maxdepth 1ได้และมันประมวลผลเฉพาะรายการของไดเรกทอรีที่กำลังแก้ไขไม่ใช่แผนผังทั้งหมด
ShadowRanger

4

ฉันเคยastyleเยื้องรหัส C / C ++ ของฉันอีกครั้งหลังจากค้นหาแท็บและช่องว่างแบบผสม นอกจากนี้ยังมีตัวเลือกในการบังคับสไตล์รั้งโดยเฉพาะหากคุณต้องการ


4

หนึ่งสามารถใช้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 ดังนั้นสิ่งนี้อาจไม่ทำงานเลย
Martin Tournoij

@Carpetsmoker จุดที่ดีเกี่ยวกับแท็บที่จุดเริ่มต้นของบรรทัด โซลูชันใด ๆ ที่นี่จัดการกับกรณีนี้หรือไม่ สำหรับtabstopและการตั้งค่าก็จะทำงานออกหากคุณกำลังใช้expandtab vimยกเว้นว่าคุณมีโหมดบรรทัดในไฟล์
x-yuri

@ x-yuri เป็นคำถามที่ดี แต่โดยทั่วไปมักมาก คนส่วนใหญ่ใช้ \ t ไม่ใช่แท็บจริงตามตัวอักษร
Ricardo Cruz

4

คำแนะนำของฉันคือการใช้:

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

ความคิดเห็นที่:

  1. ใช้ในสถานที่แก้ไข เก็บข้อมูลสำรองใน VCS ไม่จำเป็นต้องสร้างไฟล์ * .orig เป็นวิธีปฏิบัติที่ดีที่จะให้ผลลัพธ์ที่แตกต่างกับการกระทำครั้งสุดท้ายของคุณเพื่อให้แน่ใจว่าสิ่งนี้ทำงานได้ตามที่คาดหวังไม่ว่าในกรณีใด ๆ
  2. sedเป็นตัวแก้ไขสตรีม ใช้exสำหรับการแก้ไขในสถานที่ นี้หลีกเลี่ยงการสร้างไฟล์ temp พิเศษและเปลือกหอยวางไข่แต่ละทดแทนในขณะที่คำตอบด้านบน
  3. คำเตือน: สิ่งนี้จะยุ่งกับแท็บทั้งหมดไม่ใช่เฉพาะที่ใช้สำหรับการเยื้อง นอกจากนี้มันไม่ได้ทำการแทนที่บริบทที่รับรู้ของแท็บ นี่เพียงพอสำหรับกรณีการใช้ของฉัน แต่อาจไม่เป็นที่ยอมรับสำหรับคุณ
  4. แก้ไข: รุ่นก่อนหน้าของคำตอบนี้มาใช้แทนfind|xargs find -execดังที่ชี้ให้เห็นโดย @ gniourf-gniourf สิ่งนี้นำไปสู่ปัญหาเกี่ยวกับช่องว่างราคาและตัวควบคุมในชื่อไฟล์ cf ล้อ

exอาจไม่สามารถใช้ได้กับทุกระบบ Unix การแทนที่ด้วยvi -eอาจใช้กับเครื่องจักรได้มากกว่า นอกจากนี้ regex ของคุณจะแทนที่อักขระแท็บเริ่มต้นจำนวนเท่าใดก็ได้ด้วยช่องว่างสองช่อง แทนที่ regex โดย+%s/\t/ /gไม่ทำลายการเยื้องหลายระดับ อย่างไรก็ตามสิ่งนี้ยังมีผลกับอักขระแท็บที่ไม่ได้ใช้สำหรับการเยื้อง
Lukas Schmelzeisen

ex เป็นส่วนหนึ่งของ POSIX [1] ดังนั้นควรใช้งานได้ ข้อดีของการทำดัชนีหลายระดับ ฉันใช้/\t/ /ตัวแปรกับไฟล์ของฉันจริง ๆแต่เลือกที่/\t\+//จะไม่แบ่งแท็บที่ไม่มีการเยื้อง พลาดปัญหากับการเยื้องแบบหลายอย่าง! การอัพเดตคำตอบ [1] man7.org/linux/man-pages/man1/ex.1p.html#SEE%C2%A0ALSO
Heinrich Hartmann

2
การใช้xargsวิธีนี้ไม่มีประโยชน์ไร้ประสิทธิภาพและไม่สมบูรณ์ (คิดชื่อไฟล์ที่มีช่องว่างหรือเครื่องหมายคำพูด) ทำไมคุณไม่ใช้findของ-execสวิทช์แทน?
gniourf_gniourf

ฉันขอยืนยันว่าชื่อไฟล์ที่มีช่องว่างและเครื่องหมายคำพูดแตก; ) หากคุณต้องการการสนับสนุนที่ฉันต้องการ: -print0ตัวเลือกในการค้นหา / xargs ฉันชอบ xargs มากกว่า-execเนื่องจาก: a) การแยกข้อกังวล b) มันสามารถสลับกับ GNU ขนานได้ง่ายขึ้น
เฮ็น Hartmann

อัปเดตการเพิ่มความคิดเห็น @gniourf_gniourf แล้ว
Heinrich Hartmann

4

ในการแปลงไฟล์ Java ทั้งหมดซ้ำในไดเรกทอรีให้ใช้ 4 ช่องว่างแทนแท็บ:

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

วิธีการคือคำตอบที่แตกต่างกันนี้จากนี้ซึ่งได้รับการโพสต์ 4 ปีที่ผ่านมา?
PP

2
คำตอบของคุณก็เช่นกัน อันที่จริงนี่เป็นคำตอบที่ด้อยกว่าของ Gene: 1) คำตอบของ Gene จะดูแลไดเรกทอรีที่มีชื่อเดียวกัน 2) มันไม่ย้ายหากการขยายล้มเหลว
PP

4

คุณสามารถใช้findกับtabs-to-spacesแพ็คเกจสำหรับสิ่งนี้

ก่อนติดตั้ง tabs-to-spaces

npm install -g tabs-to-spaces

จากนั้นเรียกใช้คำสั่งนี้จากไดเรกทอรีรากของโครงการของคุณ

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

สิ่งนี้จะแทนที่tabอักขระทั้งหมดด้วย 2 spacesในทุก ๆ ไฟล์


3

ไม่มีร่างกายพูดถึงrpl? ใช้ rpl คุณสามารถแทนที่สตริงใด ๆ ในการแปลงแท็บเป็นช่องว่าง

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

ง่ายมาก.


1
สิ่งนี้เสียหายไฟล์ไบนารีทั้งหมดใน repo ของฉัน
Aaron Franke

1
คำสั่งที่ยอดเยี่ยม แต่อาจเป็นอันตรายกับตัวเลือกเรียกซ้ำและไฟล์ทั้งหมดในโฟลเดอร์ตามที่ระบุข้างต้น ฉันจะเพิ่ม --dry-run ตัวเลือก "ในกรณี" เพื่อให้แน่ใจว่าคุณกำลังนั่งอยู่ในโฟลเดอร์ด้านขวา
MortimerCat

2

การใช้expandคำแนะนำในคำตอบอื่น ๆ ดูเหมือนจะเป็นวิธีการที่มีเหตุผลที่สุดสำหรับงานนี้เพียงอย่างเดียว

ที่กล่าวว่าสามารถทำกับ Bash และ Awk ในกรณีที่คุณอาจต้องการแก้ไขอื่น ๆ พร้อมกับมัน

หากใช้ Bash 4.0 หรือสูงกว่าสามารถใช้shopt builtin globstarเพื่อค้นหาแบบวนซ้ำ**ได้

ด้วย GNU Awk เวอร์ชั่น 4.1 หรือสูงกว่าคุณสามารถแก้ไขไฟล์ "inplace" ได้เช่น:

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

2

ดาวน์โหลดและเรียกใช้สคริปต์ต่อไปนี้เพื่อแปลงฮาร์ดแท็บซ้ำให้เป็นแท็บซอฟต์ในไฟล์ข้อความธรรมดา

เรียกใช้งานสคริปต์จากภายในโฟลเดอร์ซึ่งมีไฟล์ข้อความธรรมดา

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

วิธีการเป็นมิตรกับพื้นที่เก็บข้อมูล 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)$'

คุณอาจต้องการสิ่งนี้โดยเฉพาะอย่างยิ่งเนื่องจาก Makefiles ที่น่ารำคาญซึ่งต้องใช้แท็บ

คำสั่งgit grep --cached -Il '':

  • แสดงเฉพาะไฟล์ที่ถูกติดตามดังนั้นจึงไม่มีอะไรอยู่ข้างใน .git
  • แยกไดเรกทอรีไฟล์ไบนารี (อาจเสียหาย) และ symlink (จะถูกแปลงเป็นไฟล์ปกติ)

ตามที่อธิบายไว้ที่: จะแสดงรายการไฟล์ข้อความ (ที่ไม่ใช่ไบนารี) ทั้งหมดในที่เก็บ git ได้อย่างไร?

chmod --referenceคงสิทธิ์ของไฟล์ไว้ไม่เปลี่ยนแปลง: /unix/20645/clone-ownership-and-permissions-from-another-fileขออภัยฉันไม่พบ POSIX ทางเลือกสั้น

หาก codebase ของคุณมีความคิดที่บ้าคลั่งที่จะอนุญาตแท็บ raw ที่ทำงานได้ในสตริงให้ใช้:

expand -i

แล้วสนุกไปกับแท็บบรรทัดที่ไม่ใช่จุดเริ่มต้นทีละบรรทัดซึ่งคุณสามารถแสดงรายการด้วย: เป็นไปได้ไหมที่จะใช้ grep grep สำหรับแท็บ?

ทดสอบบน Ubuntu 18.04


-1

การแปลงแท็บเป็นพื้นที่เพียงแค่ในไฟล์ ".lua" [แท็บ -> 2 ช่องว่าง]

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

เห็นได้ชัดว่าจำนวนพื้นที่ที่แท็บขยายขึ้นอยู่กับบริบท ดังนั้น sed เป็นเครื่องมือที่ไม่เหมาะสมอย่างสมบูรณ์สำหรับงาน
สเวน

?? @Sven, คำสั่ง sed ของฉันทำสิ่งเดียวกันกับที่ขยายคำสั่ง ( expand -t 4 input >output)
Makah

3
ไม่แน่นอน expand -t 4จะขยายแท็บในa\tb3 ช่องว่างและแท็บในaa\tb2 ช่องว่างตามที่ควรจะเป็น expandคำนึงถึงบริบทของแท็บsedไม่ได้และจะแทนที่แท็บด้วยจำนวนช่องว่างที่คุณระบุโดยไม่คำนึงถึงบริบท
สเวน

-1

ใช้ vim-way:

$ ex +'bufdo retab' -cxa **/*.*
  • ทำการสำรองข้อมูล! ก่อนที่จะดำเนินการคำสั่งดังกล่าวเนื่องจากอาจทำให้ไฟล์ไบนารีของคุณเสียหาย
  • กับการใช้งานglobstar( **) shopt -s globstarสำหรับการเรียกซ้ำเปิดใช้งานโดย
  • ในการระบุประเภทไฟล์เฉพาะให้ใช้ตัวอย่าง: **/*.c.

การปรับเปลี่ยน TabStop +'set ts=2'เพิ่ม

อย่างไรก็ตามลงด้านคือว่ามันสามารถเปลี่ยนแท็บภายในสตริง

ดังนั้นเพื่อการแก้ปัญหาที่ดีขึ้นเล็กน้อย (โดยใช้การทดแทน) ลอง:

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

หรือโดยใช้exโปรแกรมแก้ไข + 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 $*
}

ฉัน downvoted หลายคำตอบในกระทู้นี้ไม่เพียง แต่คุณ ;-) เหตุผลคือ:retabอาจจะไม่ทำงานที่ทั้งหมด , เปลือก globbing เป็นวิธีการแก้ปัญหาที่ไม่ดีสำหรับการจัดเรียงของสิ่งนี้ของคุณ:sสั่งจะแทนที่ใด ๆปริมาณของแท็บที่มี 2 คัน (ซึ่งคุณเกือบ ไม่ต้องการ) เริ่มอดีตเพียงเพื่อเรียกใช้:!expandกระบวนการคือโง่ ...
มาร์ติน Tournoij

... และโซลูชันทั้งหมดของคุณจะปิดบังไฟล์ไบนารีและเช่น (เช่นไฟล์. png, .pdf และอื่น ๆ )
Martin Tournoij

นี่เป็นคำแนะนำที่น่ากลัวสำหรับเอกสารอย่างตรงไปตรงมาเราต้องทำความคุ้นเคยกับไวยากรณ์ที่ทึบแสงและปัญหาทางความหมายของหลาย ๆ โปรแกรมเพื่อให้สามารถเข้าใจสิ่งนี้ได้อย่างใกล้ชิด
Josip Rodin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.