Як видалити пробіли з усіх проміжків усіх рекурсивно?


122

Як ви можете видалити всю пробільну частину цілого проекту? Починаючи з кореневого каталогу та видаляючи пробіли пробілу з усіх файлів у всіх папках.

Також я хочу мати можливість змінювати файл безпосередньо, а не просто друкувати все для stdout.


О, ви шукаєте "портативне" рішення або більш специфічне для ОС? Яку ОС ви використовуєте?
Джо Пінеда

3
Я хотів би побачити версію цього варіанту, яка б працювала на OS X Snow Leopard і ігнорувала папки .git та .svn.
Тревор Турк

Відповіді:


83

Ось ОС 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:]], щоб видалити і вкладки, і пробіли.
Лейф Грюнвольдт

21
У Гірському Леві це повертається sed: RE error: illegal byte sequenceдля мене.
Брайсон

12
Для тих, хто має проблеми з "незаконною послідовністю байтів": Введіть export LANG=Cі повторіть спробу
Георг Ледерманн

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 (s) як нащадків, тобто не всередині папок, які мають .gitкаталоги, незалежно від того, наскільки глибоко вкладені.
Ілля Москвін

Поєднуючи цю відповідь із @ deepwell's, щоб уникнути проблем із git / svnfind . -not \( -name .svn -prune -o -name .git -prune \) -type f -print0 | xargs -0 perl -pi -e 's/ +$//'
Вільям Денніс

1
Мабуть, є кращий спосіб, але я оговтався від маніпуляції git repo, клонувавши репо в окрему папку, а потім зробив, rsync -rv --exclude=.git repo/ repo2/після чого локальні зміни repoтакож були в (непошкодженому) repo2.
MatrixManAtYrService

29

Два альтернативних підходи, які також працюють з новими рядками DOS (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
Тож мені дуже подобається це git рішення. Це дійсно повинно бути на вершині. Я не хочу зберігати повернення перевезення. Але я віддаю перевагу цьому, який я поєднав у 2010 році.
odinho - Велмонт

Мій git скаржиться, що вираз -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": команда a очікує \ з наступним текстом
iamjwc

Заміна ';' з \; повинен працювати. (Також цитати навколо {} суворо не потрібні).
agnul

4
Щоб видалити всі пробіли, а не просто пробіли, слід замінити символ пробілу на [: space:] у регулярному виразі sed.
WMR

Ще одна бічна примітка: Це працює лише з версіями sed> = 4, менші версії не підтримують редагування місця.
WMR

1
Це зламало мою
грудку

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". Я не можу зовсім наслідувати твій приклад ...
Тревор Турк,

Якщо ви використовуєте tcsh, вам потрібно буде змінити подвійні лапки на одиничні. В іншому випадку ви отримаєте "Незаконне ім'я змінної". помилка.
Брендон Фосдік

GNU sed схожий, але ви робите -i.bak або --in-place = .bak, закінчуючи повною командою find dir -not -path '.git' -iname '*.py' -print0 | xargs -0 sed --in-place=.bak 's/[[:space:]]*$//'. Замініть dirвідповідний каталог як найвищий рівень для повторного відвідування.
Девід Гарднер

sed -i .bak? Чи не повинно бути sed -i.bak(без місця)?
Ondra Žižka

9

Ак був зроблений для такого роду завдань.

Він працює як греп, але знає, що не спускатися на такі місця, як .svn, .git, .cvs тощо.

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

Набагато простіше, ніж стрибати через обручі з find / grep.

Ack доступний через більшість менеджерів пакетів (як ack або ack-grep ).

Це просто програма Perl, тому вона також доступна в однофайловій версії, яку ви можете просто завантажити та запустити. Див.: Встановити Ack


ackчудово. Використовували його протягом декількох років і доступні майже в усіх пакеті репостів для більшості дистрибутивів.
Феліпе Альварес

8

ex

Спробуйте скористатися редактором Ex (частина Vim):

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

Примітка. Для рекурсії (bash4 & zsh) ми використовуємо новий варіант глобалізації ( **/*.*). Увімкнути 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" {} \;

що рекомендується способом Spring Framework Code Style .


find . -type f -name "*.java" -exec perl -p -i -e "s/[ \t]$//g" {} \;видаляє лише один пробіл замість усіх.
Карл Ріхтер

6

Зрештою, я не використовую файли пошуку та створення резервних копій.

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

Залежно від глибини дерева файлів, ця (скорочена версія) може бути достатньою для ваших потреб.

ПРИМІТКА. Це також займає, наприклад, двійкові файли.


Для конкретних файлів: знайти. -ім'я '* .rb' | xargs -I {} sed -i '' 's / [[: space:]] * $ // g' {}
Гаутам Реге

Вам не потрібен параметр '' для 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-файлів.

Оновлення 2 : Тепер він замінює всі види пробілів у кінці рядка (що означає також вкладки)


4
Я не знаю, що відбувається, але це цілком розпалило мою репо-гіт і переплутало мої образи. ЛЮДИ, БУТИ БОЛЬШЕ ДЕРЖАВНИМ, ЩО Я МАЮ!
mattalxndr

Так, це знищить двійкові файли. Однак він взагалі не повинен торкатися вашого git repo, оскільки він пропускає все, що знаходиться всередині папки .git. Але, можливо, тільки якщо ви знаходитесь в одній папці.
odinho - Велмонт,

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''якщо він -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

Це те, що для мене працює (Mac OS 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/' \{} \;

Вилучені пробіли, заміняючи вкладки пробілами, замінює CRLF Windows на Unix \n.

Що цікаво, це те, що я маю запустити це 3-4 рази, перш ніж усі файли виправляються, згідно з усіма gsedінструкціями щодо очищення .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.