Как использовать форматирование строки bash, чтобы изменить формат даты? - PullRequest
0 голосов
/ 10 мая 2018

У меня есть много файлов с именами: MM-DD-YYYY.pdf. Я хочу переименовать их в YYYY-MM-DD.pdf Я уверен, что для этого есть какая-то магия Баш. Что это?

Ответы [ 4 ]

0 голосов
/ 10 мая 2018

Для этих простых имен файлов, используя более подробный шаблон, вы можете немного упростить тело цикла:

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

Это в основном @ ответ Кусалананды , но безмногословие соответствия регулярному выражению.

0 голосов
/ 10 мая 2018

Вы можете использовать следующую команду, очень близкую к команде 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

0 голосов
/ 10 мая 2018

Для файлов в текущем каталоге:

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, чтобы увидеть, что он делает то, что вы хотите).

0 голосов
/ 10 мая 2018

Пример прямого захода из командной строки:

$ 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 число Выполнить команду, используя как можно больше стандартных входных аргументов, максимум до числовых аргументов.

...