จะลบช่องว่างต่อท้ายของไฟล์ทั้งหมดแบบวนซ้ำได้อย่างไร?


122

คุณจะลบช่องว่างต่อท้ายทั้งหมดของโปรเจ็กต์ทั้งหมดได้อย่างไร เริ่มต้นที่ไดเร็กทอรีรูทและลบช่องว่างต่อท้ายออกจากไฟล์ทั้งหมดในโฟลเดอร์ทั้งหมด

นอกจากนี้ฉันต้องการที่จะสามารถแก้ไขไฟล์ได้โดยตรงและไม่ใช่แค่พิมพ์ทุกอย่างเป็น stdout เท่านั้น


คุณกำลังมองหาโซลูชัน "พกพา" หรือระบบปฏิบัติการเฉพาะ คุณใช้ระบบปฏิบัติการอะไร
Joe Pineda

3
ฉันอยากเห็นเวอร์ชันนี้ที่ใช้งานได้กับ OS X Snow Leopard และจะไม่สนใจโฟลเดอร์. git และ. svn
Trevor Turk

คำตอบ:


83

นี่คือโซลูชัน OS X> = 10.6 Snow Leopard

มันละเว้นโฟลเดอร์. git และ. svnและเนื้อหา นอกจากนี้จะไม่ทิ้งไฟล์สำรอง

export LC_CTYPE=C
export LANG=C
find . -not \( -name .svn -prune -o -name .git -prune \) -type f -print0 | xargs -0 sed -i '' -E "s/[[:space:]]*$//"

10
คุณสามารถทำให้เร็วขึ้นได้โดยใช้\+แทน*ในสตริงแทนที่ - มิฉะนั้นจะตรงกันทุกบรรทัด
l0b0

10
คุณสามารถใช้ [[: blank:]] เพื่อลบทั้งแท็บและช่องว่าง
Leif Gruenwoldt

21
ใน Mountain Lion ผลตอบแทนsed: RE error: illegal byte sequenceสำหรับฉัน
Bryson

12
สำหรับผู้ที่มีปัญหาเกี่ยวกับ "ลำดับไบต์ที่ผิดกฎหมาย": ป้อนexport LANG=Cและลองอีกครั้ง
Georg Ledermann

3
ใน OS X 10.9 ฉันต้องการexport LC_CTYPE=C เช่นกัน: stackoverflow.com/questions/19242275/…
kissgyorgy

31

ใช้:

find . -type f -print0 | xargs -0 perl -pi.bak -e 's/ +$//'

หากคุณไม่ต้องการสร้างไฟล์ ".bak":

find . -type f -print0 | xargs -0 perl -pi -e 's/ +$//'

ในฐานะผู้ใช้ zsh คุณสามารถละเว้นการโทรเพื่อค้นหาและใช้:

perl -pi -e 's/ +$//' **/*

หมายเหตุ: เพื่อป้องกันการทำลายไดเรกทอรีลองเพิ่ม:.git-not -iwholename '*.git*'


37
อย่าลองทำใน git repo เพราะอาจทำให้ที่เก็บข้อมูลภายในของ git เสียหายได้
mgold

11
@mgold สายเกินไป grrr; /
kenorb

3
เพื่อความชัดเจนมันเป็นเรื่องปกติที่จะเรียกใช้สิ่งนี้ภายในโฟลเดอร์ย่อยของ git repo ไม่ใช่แค่ในโฟลเดอร์ใด ๆ ที่มี git repo เป็นลูกหลานกล่าวคือไม่ได้อยู่ในโฟลเดอร์ใด ๆ ที่มี.gitไดเรกทอรีไม่ว่าจะซ้อนกันลึกแค่ไหนก็ตาม
Illya Moskvin

การรวมคำตอบนี้กับ @ deepwell เพื่อหลีกเลี่ยงปัญหา git / svnfind . -not \( -name .svn -prune -o -name .git -prune \) -type f -print0 | xargs -0 perl -pi -e 's/ +$//'
William Denniss

1
อาจมีวิธีที่ดีกว่า แต่ผมหายจาก mangling repo คอมไพล์กับเรื่องนี้โดยโคลนออก repo ในโฟลเดอร์ที่แยกต่างหากแล้วทำrsync -rv --exclude=.git repo/ repo2/หลังจากที่มีการเปลี่ยนแปลงในท้องถิ่นrepoก็มีความใน repo2(เสียหาย)
MatrixManAtYrService

29

ทางเลือกอีกสองวิธีที่ใช้ได้กับDOS newlines (CR / LF) และทำได้ดีทีเดียวในการหลีกเลี่ยงไฟล์ไบนารี :

โซลูชันทั่วไปซึ่งตรวจสอบว่าประเภท MIME เริ่มต้นด้วยtext/:

while IFS= read -r -d '' -u 9
do
    if [[ "$(file -bs --mime-type -- "$REPLY")" = text/* ]]
    then
        sed -i 's/[ \t]\+\(\r\?\)$/\1/' -- "$REPLY"
    else
        echo "Skipping $REPLY" >&2
    fi
done 9< <(find . -type f -print0)

โซลูชันเฉพาะที่เก็บ Gitโดย Mat ซึ่งใช้-Iตัวเลือกในgit grepการข้ามไฟล์ที่ Git ถือว่าเป็นไบนารี:

git grep -I --name-only -z -e '' | xargs -0 sed -i 's/[ \t]\+\(\r\?\)$/\1/'

3
ผมชอบวิธีแก้ปัญหาคอมไพล์นี้มาก จริงๆมันควรจะอยู่ด้านบน ฉันไม่ต้องการบันทึกการคืนรถม้า แต่ฉันชอบสิ่งนี้กับสิ่งที่ฉันรวมในปี 2010
odinho - Velmont

คอมไพล์ของฉันบ่นว่านิพจน์ -e ว่างเปล่า แต่ใช้งานได้ดีเมื่อใช้ -e '. *'
muirbot

@okor ใน GNU sedตัวเลือกต่อท้าย-iเป็นทางเลือกแต่ในBSDsedไม่ใช่ มันไม่จำเป็นต้องพูดอย่างเคร่งครัดที่นี่ดังนั้นฉันจะลบออก
l0b0

24

ใน Bash:

find dir -type f -exec sed -i 's/ *$//' '{}' ';'

หมายเหตุ: หากคุณกำลังใช้ที่.gitเก็บลองเพิ่ม: -not -iwholename '.git'.


ซึ่งทำให้เกิดข้อผิดพลาดเช่นนี้สำหรับทุกไฟล์ที่พบ sed: 1: "dir / file.txt": command a
expected

แทนที่ ';' ด้วย \; ควรทำงาน. (นอกจากนี้ยังไม่จำเป็นต้องใช้เครื่องหมายคำพูดรอบ ๆ {})
agnul

4
ในการลบช่องว่างทั้งหมดไม่ใช่แค่ช่องว่างคุณควรแทนที่อักขระช่องว่างด้วย [: space:] ในนิพจน์ทั่วไปของคุณ
WMR

หมายเหตุด้านอื่น: ใช้ได้เฉพาะกับรุ่น sed> = 4 เวอร์ชันที่เล็กกว่าไม่รองรับการแก้ไข
WMR

1
สิ่งนี้ทำให้ฉันเข้าใจผิด :(
CrabMan

14

สิ่งนี้ใช้ได้สำหรับฉันใน OSX 10.5 Leopard ซึ่งไม่ใช้ GNU sed หรือ xargs

find dir -type f -print0 | xargs -0 sed -i.bak -E "s/[[:space:]]*$//"

โปรดใช้ความระมัดระวังหากคุณมีไฟล์ที่ต้องยกเว้น (ฉันทำ)!

คุณสามารถใช้ -prune เพื่อละเว้นไดเรกทอรีหรือไฟล์บางไฟล์ สำหรับไฟล์ Python ในที่เก็บ git คุณสามารถใช้สิ่งต่างๆเช่น:

find dir -not -path '.git' -iname '*.py'

มีโอกาสที่คุณจะชี้แจงเรื่องนี้ได้หรือไม่? ฉันต้องการคำสั่งที่จะลบช่องว่างต่อท้ายออกจากไฟล์ทั้งหมดในไดเร็กทอรีแบบวนซ้ำโดยไม่สนใจไดเร็กทอรี ".git" ฉันไม่สามารถทำตามตัวอย่างของคุณได้ ...
Trevor Turk

หากคุณใช้ tcsh คุณจะต้องเปลี่ยนอัญประกาศเป็นเครื่องหมายคำพูดเดี่ยว มิฉะนั้นคุณจะได้รับ "ชื่อตัวแปรที่ไม่ถูกต้อง" ความผิดพลาด
Brandon Fosdick

GNU sed นั้นคล้ายกัน แต่คุณทำ -i.bak หรือ --in-place = .bak ลงท้ายด้วยคำสั่งแบบเต็มของfind dir -not -path '.git' -iname '*.py' -print0 | xargs -0 sed --in-place=.bak 's/[[:space:]]*$//'. แทนที่dirด้วยไดเร็กทอรีที่เป็นปัญหาเป็นระดับบนสุดเพื่อเรียกคืน
David Gardner

sed -i .bak? มันควรจะเป็นsed -i.bak(โดยไม่เว้นวรรค) ไม่ใช่หรือ?
Ondra Žižka

9

Ack ถูกสร้างมาเพื่องานประเภทนี้

มันใช้งานได้เหมือน grep แต่รู้ว่าจะไม่ลงไปในที่ต่างๆเช่น. svn, .git, .cvs เป็นต้น

ack --print0 -l '[ \t]+$' | xargs -0 -n1 perl -pi -e 's/[ \t]+$//'

ง่ายกว่าการกระโดดผ่านห่วงด้วย find / grep

Ack สามารถใช้ได้ผ่านทางผู้จัดการแพ็คเกจส่วนใหญ่ (เช่นackหรือack-grep )

มันเป็นเพียงโปรแกรม Perl ดังนั้นจึงมีให้บริการในเวอร์ชันไฟล์เดียวที่คุณสามารถดาวน์โหลดและเรียกใช้ได้ โปรดดูที่Ack Install


ackเป็นเรื่องที่ยอดเยี่ยม ใช้งานมาหลายปีแล้วและมีให้ใช้งานในแพ็คเกจ repos เกือบทั้งหมดสำหรับ distros ส่วนใหญ่
Felipe Alvarez

8

ex

ลองใช้Ex editor (ส่วนหนึ่งของ Vim):

$ ex +'bufdo!%s/\s\+$//e' -cxa **/*.*

หมายเหตุ: สำหรับการเรียกซ้ำ (bash4 & zsh) เราใช้ตัวเลือก globbing ใหม่ ( **/*.*) เปิดใช้งานโดยshopt -s globstar .

คุณสามารถเพิ่มฟังก์ชันต่อไปนี้ลงใน.bash_profile:

# Strip trailing whitespaces.
# Usage: trim *.*
# See: https://stackoverflow.com/q/10711051/55075
trim() {
  ex +'bufdo!%s/\s\+$//e' -cxa $*
}

sed

สำหรับการใช้งานsedให้ตรวจสอบ: วิธีลบช่องว่างต่อท้ายด้วย sed?

find

ค้นหาสคริปต์ต่อไปนี้ (เช่นremove_trail_spaces.sh) สำหรับการลบช่องว่างต่อท้ายออกจากไฟล์:

#!/bin/sh
# Script to remove trailing whitespace of all files recursively
# See: /programming/149057/how-to-remove-trailing-whitespace-of-all-files-recursively

case "$OSTYPE" in
  darwin*) # OSX 10.5 Leopard, which does not use GNU sed or xargs.
    find . -type f -not -iwholename '*.git*' -print0  | xargs -0 sed -i .bak -E "s/[[:space:]]*$//"
    find . -type f -name \*.bak -print0 | xargs -0 rm -v
    ;;
  *)
    find . -type f -not -iwholename '*.git*' -print0 | xargs -0 perl -pi -e 's/ +$//'
esac

เรียกใช้สคริปต์นี้จากไดเร็กทอรีที่คุณต้องการสแกน บน OSX ในตอนท้ายมันจะลบไฟล์ทั้งหมดที่ลงท้ายด้วย.bak .

หรือเพียงแค่:

find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g" {} \;

ซึ่งเป็นวิธีที่แนะนำโดยฤดูใบไม้ผลิกรอบสไตล์รหัส


find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g" {} \;ลบช่องว่างต่อท้ายเพียงช่องว่างเดียวแทนที่จะเป็นทั้งหมด
Karl Richter

6

ฉันไม่ได้ใช้การค้นหาและไม่สร้างไฟล์สำรอง

sed -i '' 's/[[:space:]]*$//g' **/*.*

ขึ้นอยู่กับความลึกของโครงสร้างไฟล์ (เวอร์ชันสั้นกว่า) นี้อาจเพียงพอสำหรับความต้องการของคุณ

โปรดทราบว่าสิ่งนี้ใช้ไฟล์ไบนารีด้วยเช่นกัน


สำหรับไฟล์เฉพาะ: ค้นหา. - ชื่อ '* .rb' | xargs -I {} sed -i '' s / [[: space:]] * $ // g '{}
Gautam Rege

คุณไม่ต้องการพารามิเตอร์ '' สำหรับ sed; หรือฉันอาจจะขาดอะไรไป ฉันลองใช้กับไฟล์ทั้งหมดในไดเร็กทอรีที่กำหนดเช่นนี้ sed -i 's / [[: space:]] * $ // g' util / *. m
Mircea

6

แทนที่จะยกเว้นไฟล์นี่คือรูปแบบที่แตกต่างจากด้านบนที่เป็นสีขาวอย่างชัดเจนจะแสดงรายการไฟล์ตามนามสกุลไฟล์ที่คุณต้องการถอดออกอย่าลังเลที่จะลิ้มรส:

find . \( -name *.rb -or -name *.html -or -name *.js -or -name *.coffee -or \
-name *.css -or -name *.scss -or -name *.erb -or -name *.yml -or -name *.ru \) \
-print0 | xargs -0 sed -i '' -E "s/[[:space:]]*$//"

เพื่อให้ได้ผลสำหรับฉันฉันต้องเพิ่มคำพูด:-name "*.rb*"
haroldcarr

5

ฉันลงเอยด้วยการใช้งานสิ่งนี้ซึ่งเป็นการผสมผสานระหว่างเวอร์ชัน pojo และ adams

มันจะทำความสะอาดทั้งช่องว่างต่อท้ายและช่องว่างต่อท้ายอีกรูปแบบหนึ่งคือการส่งคืนรถ:

find . -not \( -name .svn -prune -o -name .git -prune \) -type f \
  -exec sed -i 's/[:space:]+$//' \{} \;  \
  -exec sed -i 's/\r\n$/\n/' \{} \;

มันจะไม่แตะโฟลเดอร์. git ถ้ามี

แก้ไข : ทำให้ปลอดภัยขึ้นเล็กน้อยหลังจากความคิดเห็นไม่อนุญาตให้นำไฟล์ที่มี ".git" หรือ ".svn" อยู่ในนั้น แต่ระวังมันจะไปสัมผัสไฟล์ไบนารีถ้าคุณมี ใช้-iname "*.py" -or -iname "*.php"หลังจากนั้น-type fหากคุณต้องการให้สัมผัสเช่น. py และ. php-files

อัปเดต 2 : ตอนนี้แทนที่ช่องว่างทุกชนิดที่ท้ายบรรทัด (ซึ่งหมายถึงแท็บด้วย)


4
ฉันไม่รู้ว่าเกิดอะไรขึ้น แต่สิ่งนี้ทำให้ repo คอมไพล์ของฉันแย่ลงและทำให้ภาพของฉันยุ่งเหยิง ผู้คนระวังตัวมากกว่าที่ฉันเป็น!
mattalxndr

ใช่มันจะทำลายไฟล์ไบนารี อย่างไรก็ตามไม่ควรแตะ git repo ของคุณเลยเพราะมันจะข้ามสิ่งที่อยู่ใน. git-folder แต่อาจเฉพาะในกรณีที่คุณอยู่ในโฟลเดอร์เดียวกัน
odinho - Velmont

4

ใช้งานได้ดี .. เพิ่ม / ลบ - รวมสำหรับไฟล์บางประเภท:

egrep -rl ' $' --include *.c *  | xargs sed -i 's/\s\+$//g'


3

ฉันใช้นิพจน์ทั่วไป 4 ขั้นตอน:

  1. เปิดโฟลเดอร์รูทในตัวแก้ไขของคุณ (ฉันใช้ Visual Studio Code)
  2. แตะไอคอนค้นหาทางด้านซ้ายและเปิดใช้งานโหมดนิพจน์ทั่วไป
  3. ป้อน "+ \ n" ในแถบค้นหาและ "\ n" ในแถบแทนที่
  4. คลิก "แทนที่ทั้งหมด"

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


2

1) ใช้คำตอบอื่น ๆ อีก-Eมากมาย ฉันไม่แน่ใจว่าทำไมเนื่องจากเป็นตัวเลือกที่เข้ากันได้กับ BSD ที่ไม่มีเอกสาร-rควรใช้แทน

2) -i ''การใช้คำตอบอื่น นั่นควรจะเป็นเพียง-i(หรือ-i''ถ้า preffered) เพราะ-iมีคำต่อท้ายทันที

3) Git โซลูชันเฉพาะ:

git config --global alias.check-whitespace \
'git diff-tree --check $(git hash-object -t tree /dev/null) HEAD'

git check-whitespace | grep trailing | cut -d: -f1 | uniq -u -z | xargs -0 sed --in-place -e 's/[ \t]+$//'

รายการแรกลงทะเบียนนามแฝง git check-whitespaceซึ่งแสดงรายการไฟล์ที่มีช่องว่างต่อท้าย อันที่สองทำงานsedกับพวกเขา

ผมเพียง แต่ใช้\tมากกว่า[:space:]ที่ผมไม่มักจะเห็นแท็บแนวตั้งฟีดรูปแบบและช่องว่างที่ไม่เปราะ การวัดของคุณอาจแตกต่างกันไป


1

นี่คือสิ่งที่ใช้ได้ผลสำหรับฉัน (MacOS X 10.8, GNU sed ติดตั้งโดย Homebrew):

find . -path ./vendor -prune -o \
  \( -name '*.java' -o -name '*.xml' -o -name '*.css' \) \
  -exec gsed -i -E 's/\t/    /' \{} \; \
  -exec gsed -i -E 's/[[:space:]]*$//' \{} \; \
  -exec gsed -i -E 's/\r\n/\n/' \{} \;

ลบออกช่องว่างต่อท้ายแทนที่แท็บที่มีช่องว่างแทนที่ของ Windows CRLF \nกับระบบปฏิบัติการยูนิกซ์

สิ่งที่น่าสนใจคือฉันต้องเรียกใช้สิ่งนี้ 3-4 ครั้งก่อนที่ไฟล์ทั้งหมดจะได้รับการแก้ไขโดยgsedคำแนะนำในการทำความสะอาดทั้งหมด

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