Перетворення вкладок у пробіли у багатьох файлах


11

У мене дуже багато файлів із вкладеними вкладками, і я хотів би перетворити їх у пробіли. Я знаю про expandкоманду, але, на жаль, мені доведеться набрати кожен файл, використовуючи її. Чи є простіший спосіб зробити це в Linux?

Відповіді:


12

Спробуйте наступне:

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

Якщо вам потрібно чотири пробіли, спробуйте:

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

Це замінить кожну вкладку одним пробілом. Оскільки людина, згадана з використанням expand, я припускаю, що він / він хоче, щоб вирівнювання тексту було збережене.
garyjohn

Потрібно 's/\t/ /g'замінити більше однієї вкладки на рядок.
Даніель Андерссон

1
Значне прискорення, якщо є багато файлів, робить " find ./ -type f -exec sed -i ’s/\t/ /g’ {} +" (тобто " +" замість " \;"), якщо findверсія підтримує її (і я особисто не зустрічав жодної версії, яка не має, але це не стандарт POSIX , тому я думаю, що це може статися в деяких системах. Дивіться " -exec command {} +" в посібнику). Замість того, щоб запускати один екземпляр sedдля кожного файлу, це створить список аргументів з такою кількістю аргументів імен файлів, скільки підтримує система ( getconf ARG_MAX= 2097152 в моїй системі), і xargs, таким чином, запустити набагато менше sedпроцесів.
Даніель Андерссон

6
Зауважте будь-яким користувачам Mac, які виявили це: версія OS X sedне розуміє \tпослідовність виходу на вкладку. Ви можете замінити його буквальним символом вкладки, який ви можете ввести в оболонку [Ctrl]+V, [Tab].
Джеремі Бенкс каже: ЗАСТОСУЙТЕ ДОМА

expandймовірно , краще , ніж sedдля цього, як описано в: stackoverflow.com/a/11094620/131824
Девід Вейнрауб

6

Існує маса способів зробити це. Існує також безліч способів застрелити себе в ногу, роблячи це, якщо ви не обережні або якщо ви не знайомі з Linux, як здається. Якщо припустити, що ви можете створити список файлів, які ви хочете перетворити, використовуючи щось на кшталт findабо вручну з редактором, просто передайте цей список у наступне.

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

Один із способів можна застрелити себе в ногу - це зробити помилку, щоб ви завершили введення порожнього файлу на всі вказані вами імена файлів, тим самим видаливши вміст усіх своїх файлів. Тому будьте обережні і протестуйте все, що ви робите спочатку, на невеликому наборі файлів, які ви створили.


3
Зробіть mvумовою успішність expand:expand ... && mv ...
Призупинено до подальшого повідомлення.

Не забудьте expand -t 4розширити вкладки на 4 місця. Також за допомогою цього методу можна створювати останні рядки. Але інакше це працює.
mgold

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

-I foo створює шаблон змінної foo для кожного рядка введення, тому ви можете звертатися до входу не один раз.

-print0і -0скажіть обом командам використовувати \ 0 як роздільник рядків замість SPACE, тому ця команда працює для шляхів з пробілами.


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

Мінуси:
файли, що перевищують розмір буфера труби ( 64 КБ ), врізаються

Плюси:
жодні файли тимчасових файлів, що
перевищують розмір буфера труб, не врізаються


0

Це краще:

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

3
Чому це краще? Це не чудова ідея використовувати, /tmp/eтому що якщо цей файл використовує щось інше, це зіпсує його. Як би, якщо двоє користувачів хотіли використовувати це одночасно.
Кевін Панько

0

Я дав цю проблему з урахуванням таких вимог:

  • Фільтруйте файли на основі їх імен, щоб обробити, наприклад, лише .cpp або .json файл
  • Підтримка паралельної обробки. Якщо файлів багато, це може забезпечити величезну швидкість
  • Розчин повинен вміщуватися в одну лінію для зручного використання

Останню вимогу було найважче виконати, оскільки "розширення" не дозволяє змінювати файли на місці.

Я придумав таке рішення:

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'

Ось кілька пояснень:

  • "find" знаходить файли для обробки. "-regextype egrep" дозволяє фільтрувати їх на основі їх імені та регулярного виразу у форматі "egrep"
  • Параметр "-типу f" гарантує, що ми будемо відповідати лише звичайним файлам, а не каталогів або іншим спеціальним
  • Параметр "-regexp" - це власне регулярне вираження, яке відповідає в цьому випадку будь-якому файлу, який закінчується .c, .cpp, .h або .hpp (все ім'я повинно збігатися, тому "file.c2" не буде , що ми хочемо)
  • "-print0" вказує "знайти" друкувати шляхи до файлу на його стандартному виході з символом 0 в кінці кожного шляху. Разом з опцією "-0" для "xargs" вона дозволяє передавати імена, що містять зворотні каретки, від одного інструмента до іншого (навіть якщо це досить рідкісна ситуація ...)
  • xargs запускає новий процес для кожного шляху ("-n 1"), але може запускати 10 процесів паралельно ("-P 10")
  • xargs використовує псевдонім "FILE" для передачі кожного шляху файлу до команди, яка є скриптом bash
  • скрипт bash викликає "розширити" і зберігає результат у тимчасовому файлі, імена якого містить поточний ідентифікатор процесу ($$), так що всі процеси, що працюють паралельно в заданому файлі, використовують різні тимчасові файли
  • вся команда використовує шаблон (command1 && command2 && command3), щоб процес зупинився, якщо будь-яка підкоманда поверне помилку
  • якщо з попереднього ланцюжка "&&" є помилка, скрипт bash поверне код виходу 255, що призведе до негайного припинення xargs
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.