Как использовать форматирование строки bash, чтобы изменить формат даты?
У меня есть много файлов, которые названы как: MM-DD-YYYY.pdf
, Я хочу переименовать их как YYYY-MM-DD.pdf
Я уверен, что есть немного магии Баша, чтобы сделать это. Что это?
4 ответа
Для файлов в текущем каталоге:
for name in ./??-??-????.pdf; do
if [[ "$name" =~ (.*)/([0-9]{2})-([0-9]{2})-([0-9]{4})\.pdf ]]; then
echo mv "$name" "${BASH_REMATCH[1]}/${BASH_REMATCH[4]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]}.pdf"
fi
done
Рекурсивно, в или под текущим каталогом:
find . -type f -name '??-??-????.pdf' -exec bash -c '
for name do
if [[ "$name" =~ (.*)/([0-9]{2})-([0-9]{2})-([0-9]{4})\.pdf ]]; then
echo mv "$name" "${BASH_REMATCH[1]}/${BASH_REMATCH[4]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]}.pdf"
fi
done' bash {} +
Включение globstar
опция оболочки в bash
Позвольте нам сделать следующее (также, как и вышеупомянутое решение, обработаем все файлы в текущем каталоге или ниже):
shopt -s globstar
for name in **/??-??-????.pdf; do
if [[ "$name" =~ (.*)/([0-9]{2})-([0-9]{2})-([0-9]{4})\.pdf ]]; then
echo mv "$name" "${BASH_REMATCH[1]}/${BASH_REMATCH[4]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]}.pdf"
fi
done
Все три из этих решений используют регулярное выражение для выбора соответствующих частей имен файлов, а затем переставляют эти части в новое имя. Единственная разница между ними заключается в том, как создается список путей.
Префиксы кода mv
с echo
для безопасности. Чтобы фактически переименовать файлы, удалите echo
(но запустить хотя бы один раз с echo
чтобы увидеть, что он делает то, что вы хотите).
Пример прямого подхода из командной строки:
$ ls
10-01-2018.pdf 11-01-2018.pdf 12-01-2018.pdf
$ ls [0-9]*-[0-9]*-[0-9]*.pdf|sed -r 'p;s/([0-9]{2})-([0-9]{2})-([0-9]{4})/\3-\1-\2/'|xargs -n2 mv
$ ls
2018-10-01.pdf 2018-11-01.pdf 2018-12-01.pdf
ls
выход по трубопроводу sed
, затем мы используем флаг p для печати аргумента без изменений, другими словами, оригинальное имя файла, и s для выполнения и вывода преобразования.
ls
+ sed
Результатом является комбинированный вывод, который состоит из последовательности old_file_name и new_file_name.
Наконец, мы пропускаем полученную подачу через xargs
чтобы получить эффективное переименование файлов.
От xargs
мужчина:
-n число Выполнить команду, используя как можно больше стандартных входных аргументов, максимум до числа аргументов.
Для этих простых имен файлов, используя более подробный шаблон, вы можете немного упростить тело цикла:
twodigit=[[:digit:]][[:digit:]]
fourdigit="$twodigit$twodigit"
for f in $twodigit-$twodigit-$fourdigit.pdf; do
IFS=- read month day year <<< "${f%.pdf}"
mv "$f" "$year-$month-$day.pdf"
done
Это в основном ответ @Kusalananda, но без многословия сопоставления регулярных выражений.
Вы можете использовать следующую команду, очень klashxx на klashxx:
for f in *.pdf; do echo "$f"; mv "$f" "$(echo "$f" | sed 's@\(..\)-\(..\)-\(....\)@\3-\2-\1@')"; done
до:
ls *.pdf
12-01-1998.pdf 12-03-2018.pdf
после:
ls *.pdf
1998-01-12.pdf 2018-03-12.pdf
Также, если у вас есть другие pdf
файлы, которые не соответствуют этому формату в вашей папке, вы можете выбрать только те файлы, которые соответствуют формату: MM-DD-YYYY.pdf
Для этого используйте следующую команду:
for f in `find . -maxdepth 1 -type f -regextype sed -regex './[0-9]\{2\}-[0-9]\{2\}-[0-9]\{4\}.pdf' | xargs -n1 basename`; do echo "$f"; mv "$f" "$(echo "$f" | sed 's@\(..\)-\(..\)-\(....\)@\3-\2-\1@')"; done
Пояснения:
find . -maxdepth 1 -type f -regextype sed -regex './[0-9]\{2\}-[0-9]\{2\}-[0-9]\{4\}.pdf
Эта команда поиска будет искать только те файлы в текущем рабочем каталоге, которые соответствуют вашему синтаксису, и извлекать их базовое имя (удалите./
вначале папки и другие типы файлов, которые будут иметь одинаковые имена, не учитываются, другие*.pdf
файлы также игнорируются.for each file
Вы делаете перемещение, и полученное имя файла вычисляется с использованием sed и обратной ссылки на 3 группы для MM,DD и YYYY.