Переименуйте файл с помощью grep и for

Переименуйте файл с помощью grep и for

Я хотел бы переименовать файлы со следующими расширениями: .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.

Связанный контент