
Я хотел бы переименовать файлы со следующими расширениями: .txt, .data, .conf в ".xml"
привет.txt -> привет.xml
Для этого файл также должен содержать следующую строку:<?xml version="1.0" encoding="UTF-8"?>
Вот что у меня есть:
for file in *
do
if [ $(grep -Rc '<?xml version="1.0" encoding="UTF-8"?>' --include ".txt" --include ".data" --include "*.conf") = true ]
then
rename extension to: .xml
fi
done
Есть идеи?
решение1
Если вынуждатьсясделать это с помощью grep
и for
, возможно, что-то вроде этого?
grep -RlZ '<?xml version="1.0" encoding="UTF-8"?>' --include "*.txt" --include "*.data" --include "*.conf" |
xargs -0 sh -c 'for f; do echo mv -- "$f" "${f%.*}.xml"; done' sh
(удалите его, echo
как только убедитесь, что он работает правильно).
grep -RlZ
выводит список имен файлов, в которых найдены совпадения, разделенный нулемxargs -0
передает этот список, разделенный нулем, вsh -c
for f
циклы по именам файлов как позиционным параметрам
или (если вам разрешено использовать while
вместо for
) вы можете пропустить xargs
и дополнительный скриптлет оболочки, например
grep -RlZ '<?xml version="1.0" encoding="UTF-8"?>' --include "*.txt" --include "*.data" --include "*.conf" |
while IFS= read -r -d '' f; do echo mv -- "$f" "${f%.*}.xml"; done
решение2
find . -type f \( -name "*.txt" -o -name "*.data" -o -name "*.conf" \) -exec sh -c '
for file in "$@"; do
if grep -qF "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" "$file"; then
mv -- "$file" "${file%.*}.xml"
fi
done
' findshell {} +
Я думаю, find
что более адекватно в этом контексте. Он рекурсивно ищет обычные файлы с расширениями .txt
, .data
и .conf
и проверяет, присутствует ли указанная вами строка в каждом из них. Если да, то он изменит расширение на .xml
командой mv
.
Если вы не уверены, будет ли код работать так, как ожидается, вы можете добавить echo
предыдущую часть mv
, чтобы увидеть, что он делает.
Я также должен упомянуть, что этот скрипт не зависит от не-POSIX-утилиты.
решение3
Вы можете попробовать это:
for file in *.{txt,conf}; do
[[ $(grep "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" "$file") ]] && \
mv "$file" "${file%.*}.xml" || echo "$file" " does not match"
done
решение4
С использованием bash
:
shopt -s globstar dotglob nullglob extglob
string='<?xml version="1.0" encoding="UTF-8"?>'
for pathname in ./**/*.@(txt|data|conf); do
if [[ -f $pathname ]] && grep -q -F "$string" "$pathname"; then
mv -i "$pathname" "${pathname%.*}.xml"
fi
done
Я начинаю с установки ряда параметров оболочки, которые обычно не устанавливаются bash
по умолчанию:
globstar
включает**
шаблон подстановки, который рекурсивно сопоставляется с подкаталогами.dotglob
заставляет шаблоны подстановки соответствовать скрытым именам.nullglob
заставляет несовпадающий шаблон полностью исчезнуть, а не оставаться нераскрытым. Это гарантирует, что наш цикл позже вообще не будет запущен, если совпадений не будет.extglob
включить расширенные шаблоны подстановки, например,@(txt|data|conf)
соответствующие одной из строк внутри скобок.
Затем мы циклически перебираем имена кандидатов и проверяем каждое из них на наличие заданной строки. Если строка найдена, файл переименовывается путем замены суффикса имени файла после последнего символа точки на xml
.