Найдите все файлы в директории и примените команды к каждому из них.

Вопрос или проблема

Я хочу применить команды ниже ко всем файлам в директории, а не к одному файлу.

cat file.txt | sed -E "s/\@([0-9]+)\W+~(.*?)/\1 \2/g" | tr -d '~'

cat file.txt | sed -E "s/\@([0-9]+).*\~(.*)[~\r\n]/\1 \2/g" | sed -E "s/([0-9]+)\W+(.*)/\@\1\ = ~\2~/g"

С zsh вместо bash:

for file in some/dir/*(ND-.); do
  sed -Ee 's/@([0-9]+)\W+~/\1 /g; s/~//g' -- $file &&
    sed -Ee 's/@([0-9]+).*~(.*)[~\r]/\1 \2/g
             s/([0-9]+)\W+(.*)/@\1\ = ~\2~/g' -- $file
done

Где ND-. ограничивает типы файлов до обычных (определяемых после разрешения символических ссылок с -) и включая Dоточенные файлы (скрытые файлы).

Я удалил несколько обратных слешей, которые были не только лишними, но также потенциально могут не сработать в будущем, так как вы можете обнаружить, что \@ или \~ могут иметь специальное значение в будущих версиях sed, \n, что не имеет смысла, так как sed работает с содержимым строк, что не включает разделители строк.

Я также убрал (.*?), который в реализациях sed, признающих этот оператор perl (а таких немного), был бы бессмысленным, так как он соответствовал бы только пустой строке.

Кроме того, я не могу дальше комментировать, имеет ли смысл это замещение, так как вы не уточнили, что оно должно делать.

В bash это возможно, но более громоздко:

shopt -s nullglob dotglob
for file in some/dir/*; do
  [ -f "$file" ] || continue
  sed -Ee 's/@([0-9]+)\W+~/\1 /g; s/~//g' -- "$file" &&
    sed -Ee 's/@([0-9]+).*~(.*)[~\r]/\1 \2/g
             s/([0-9]+)\W+(.*)/@\1\ = ~\2~/g' -- "$file"
done

[‘s -f также проверяет тип файлов после разрешения символических ссылок, измените на [ -f "$file" ] && [ ! -L "$file" ], чтобы исключить символические ссылки.

С реализацией find от GNU вы также можете сделать:

find -H some/dir -mindepth 1 -maxdepth 1 -xtype f \
  -exec sed -Ee 's/@([0-9]+)\W+~/\1 /g; s/~//g' -- {} ';' \
  -exec sed -Ee 's/@([0-9]+).*~(.*)[~\r]/\1 \2/g
                 s/([0-9]+)\W+(.*)/@\1\ = ~\2~/g' -- {} ';'

Но будьте осторожны, список файлов не отсортирован, так что вы получите их в, казалось бы, случайном порядке. Исключение скрытых файлов (эквивалент удаления D или dotglob выше) также потребует ! -name '.*', что, чтобы быть надежным, должно выполняться в локали C, что повлияет на соответствие sed, поэтому вам понадобится что-то вроде:

LC_ALL=C find -H some/dir -mindepth 1 -maxdepth 1 ! -name '.*' -xtype f \
  -exec env -u LC_ALL sed -Ee 's/@([0-9]+)\W+~/\1 /g; s/~//g' -- {} ';' \
  -exec env -u LC_ALL sed -Ee 's/@([0-9]+).*~(.*)[~\r]/\1 \2/g
                               s/([0-9]+)\W+(.*)/@\1\ = ~\2~/g' -- {} ';'

(что предполагает, что LC_ALL изначально не был установлен), где мы устанавливаем локаль на C для find, но возвращаем ее для sed.

Ответ или решение

Для решения задачи по применению команд к каждому файлу в директории, можно воспользоваться рядом инструментов в командной строке, включая оболочку zsh и утилиты sed и find. Давайте рассмотрим более подробно несколько возможных подходов.

Обработка файлов с использованием zsh

Если вы предпочитаете использовать zsh, это позволяет организовать обработку файлов с минимальными усилиями. Пример цикла для обработки всех файлов в каталоге:

for file in some/dir/*(ND-.); do
  # Первое преобразование
  sed -Ee 's/@([0-9]+)\W+~(.*?)/\1 \2/g; s/~//g' -- "$file" &&
  # Второе преобразование
  sed -Ee 's/@([0-9]+).*~(.*)[~\r]/\1 \2/g; s/([0-9]+)\W+(.*)/@\1\ = ~\2~/g' -- "$file"
done
  • Здесь ND-. используется для фильтрации только обычных файлов, включая скрытые.
  • Для каждого файла применяются две команды sed, где первое преобразование удаляет специальные символы, а второе форматирует их по заданным правилам.

Применение подхода в bash

В bash выполнение подобной задачи требует больше усилий из-за различных настроек:

shopt -s nullglob dotglob
for file in some/dir/*; do
  [ -f "$file" ] || continue
  sed -Ee 's/@([0-9]+)\W+~(.*?)/\1 \2/g; s/~//g' -- "$file" &&
  sed -Ee 's/@([0-9]+).*~(.*)[~\r]/\1 \2/g; s/([0-9]+)\W+(.*)/@\1\ = ~\2~/g' -- "$file"
done
  • Опция nullglob позволяет обрабатывать пустые результаты, а dotglob включает скрытые файлы.
  • Условие [ -f "$file" ] || continue исключает директории и другие не-файловые объекты.

Способ с использованием утилиты find

Использование find – мощный способ, который больше подходит для обработки файлов в глубокой иерархии каталогов:

find -H some/dir -mindepth 1 -maxdepth 1 -xtype f \
  -exec sed -Ee 's/@([0-9]+)\W+~(.*?)/\1 \2/g; s/~//g' -- {} ';' \
  -exec sed -Ee 's/@([0-9]+).*~(.*)[~\r]/\1 \2/g; s/([0-9]+)\W+(.*)/@\1\ = ~\2~/g' -- {} ';'
  • В данном случае -H учитывает символические ссылки, а -xtype f фильтрует только обычные файлы.
  • -exec позволяет выполнять команды непосредственно на найденных файлах.

Учтите нюансы

При использовании этих методов важно учитывать следующие нюансы:

  1. Локализация: Убедитесь, что локализация (LC_ALL) настроена правильно, чтобы избежать неожиданных результатов при обработке символов. Можно использовать LC_ALL=C для обработки с учетом стандартной локализации.
  2. Проверка на наличие символических ссылок: Если необходимо исключить символические ссылки, можно использовать дополнительные условия в командах find или bash.

Заключение

Выбор подхода зависит от ваших предпочтений и специфики задач, которые вы решаете. Каждый метод имеет свои преимущества и недостатки. Настройте команды в соответствии с вашими требованиями и структурой файлов, чтобы гарантировать, что обработка пройдет успешно. Используйте подходящий метод в зависимости от задач и удобства работы с командной строкой.

Оцените материал
Добавить комментарий

Капча загружается...