Вопрос или проблема
Я хочу применить команды ниже ко всем файлам в директории, а не к одному файлу.
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
позволяет выполнять команды непосредственно на найденных файлах.
Учтите нюансы
При использовании этих методов важно учитывать следующие нюансы:
- Локализация: Убедитесь, что локализация (
LC_ALL
) настроена правильно, чтобы избежать неожиданных результатов при обработке символов. Можно использоватьLC_ALL=C
для обработки с учетом стандартной локализации. - Проверка на наличие символических ссылок: Если необходимо исключить символические ссылки, можно использовать дополнительные условия в командах
find
илиbash
.
Заключение
Выбор подхода зависит от ваших предпочтений и специфики задач, которые вы решаете. Каждый метод имеет свои преимущества и недостатки. Настройте команды в соответствии с вашими требованиями и структурой файлов, чтобы гарантировать, что обработка пройдет успешно. Используйте подходящий метод в зависимости от задач и удобства работы с командной строкой.