2017-01-15 6 views
1

У меня есть 400 простых текстовых файлов, которые мои письма штук, все названные в качестве таковых,Попытаться автоматически переименовывать дату в именах файлов, используя Bash регулярное выражение

A prose (June 30, 2013) 
A sad story (Dec. 1, 2016) 

Части имен файлов в основном на китайском или содержат по-китайски, но я полагаю, это не имеет значения. я хочу переименовать их, чтобы быть

130630_A prose 
161201_A sad story 

с помощью Bash сценария.

Возможно, это первый раз, когда я написал сценарий Bash. Я достаточно хорошо знаком с C++, но я нахожу Bash трудным для изучения. Хотя у меня есть основное знакомство с регулярным выражением Vim, я понимаю, что регулярное выражение Bash похоже. Я в основном полагался на this reference on wildcards.

Моя попытка, как показано ниже:

#! /usr/bin/env bash 

EXT=.txt 


for name_old in "*${EXT} */*${EXT} */*/*${EXT}"; do 
    str_title=$(expr "${name_old}" : '\(.*\)(.*).*') 
    str_date=$(expr "${name_old}" : '.*(\(.*\)).*') 
    str_y=$(expr "${str_date}" : '.*\([0-9]*\).*') 
    str_m=$(expr "${str_date}" : '.*\([a-zA-Z]*\).*') 
    str_d=$(expr "${str_date}" : '.*\([0-9]*,\).*') 

    if [ ${#str_y} -eq 0 ] || [ ${#str_m} -eq 0 ] || [ ${#str_d} -eq 0 ] ; then 
     continue 
    fi 

    name_new="${name_new}${str_y:2:3}" 

    convert_month "${str_m}" hold 
    name_new="${name_new}hold" 

    if [ ${#str_d} -eq 1 ]; then 
     name_new="${name_new}0${str_d:0:0}" 
    elif [ ${#str_d} -eq 2 ]; then 
     name_new="${name_new}${str_d:0:1}" 
    fi 

    name_new="${name_new}_${str_title}" 
    mv name_old name_new 
done 

function convert_month 
{ 
    if [ "$(expr "$(1)" : '.*\(Jan\).*')" -ne "" ]; then 
     $(2)=01 
    # ... omitted for brevity 
    elif [ "$(expr "$(1)" : '.*\(Dec\).*')" -ne "" ]; then 
     $(2)=12 
    fi 
} 

Кажется, ничего не происходит. Некоторый синтаксис - это только моя догадка, поэтому я думаю, что многие шаги многие ошибаются. Но я не могу найти в Stack Overflow пример такой сложный, как этот, и я не знаю, как отлаживать.

+0

Вторая строка ввода выглядит подозрительно: «Печальная история (1 декабря 2016 года)' '' 'после' Дека' не должна быть там? – Inian

+0

Да, он есть. Это мое соглашение об именах, или было ... я решил изменить. Да, это плохо. История состоит в том, что я сожалею, что включил столько пространств и периодов и выбрал так многословный стиль именования для даты. И теперь я хочу скомпилировать их в CLI и столкнулся с огромными трудностями. – Aminopterin

ответ

0

Там, там.

В части регулярного выражения я рассмотрел возможность того, что в скобках могут быть некоторые другие символы. Например, Something (new--Dec. 1, 2013).txt Читатель может внести изменения в соответствии с вашими потребностями. Существует хорошее reference для регулярного выражения Bash.

#! /usr/bin/env bash 

# To renames, say, `Something (Dec. 13, 2016).txt` to `161213_Something.txt` 
# First parse the `()`-enclosed part in filename, called `str_date` 
# if `2016` is a substr of DATE, set YY 
# if `Dec` is a substr of DATE, set MM 
# if `13,` is a substr of DATE, set DD 

# first define functions 

function convert_year 
{ 
    local tmp=$1 
    if [ "${#tmp}" -eq 4 ]; then 
     echo "${tmp:2:2}" 
    fi 
} 

function convert_month 
{ 
    if [ "${1}" == "Jan" ]; then 
     echo "01" 
    elif [ "${1}" == "Feb" ]; then 
     echo "02" 
    elif [ "${1}" == "Mar" ]; then 
     echo "03" 
    elif [ "${1}" == "Apr" ]; then 
     echo "04" 
    elif [ "${1}" == "May" ]; then 
     echo "05" 
    elif [ "${1}" == "une" ]; then 
     echo "06" 
    elif [ "${1}" == "uly" ]; then 
     echo "07" 
    elif [ "${1}" == "Aug" ]; then 
     echo "08" 
    elif [ "${1}" == "Sep" ]; then 
     echo "09" 
    elif [ "${1}" == "Oct" ]; then 
     echo "10" 
    elif [ "${1}" == "Nov" ]; then 
     echo "11" 
    elif [ "${1}" == "Dec" ]; then 
     echo "12" 
    fi 
} 

function convert_day 
{ 
    local tmp=$1 
    if [ ${#tmp} -eq 2 ]; then 
     echo "0${tmp:0:1}" 
    elif [ ${#tmp} -eq 3 ]; then 
     echo "${tmp:0:2}" 
    fi 
} 

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 

EXT=.txt 

find . -maxdepth 3 -type f -name '*.txt' | while read -r name_file; do 
    if [[ $name_file =~ (.*)/([^/_]*)_*\(.*([A-Za-z]{3}).*_([0-9]*,).*([0-9]{4})\).*${EXT} ]] 
    then 
     yy=$(convert_year "${BASH_REMATCH[5]}") 
     mm=$(convert_month "${BASH_REMATCH[3]}") 
     dd=$(convert_day "${BASH_REMATCH[4]}") 

     name_new="${BASH_REMATCH[1]}/${yy}${mm}${dd}_${BASH_REMATCH[2]}${EXT}" 
     mv ${name_file} ${name_new} 
    fi 
done 
1

Вы можете использовать команду date преобразовать часть даты:

#!/usr/bin/env bash 
for file in *.txt; do 
    str_date="$(grep -oP '\(\K[^\)]+' <<< "$file")"; 
    date_str=$(date -d"$str_date" +%y%m%d); 
    alphachars="${file/ (*/}"; 
    ext="${file##*.}"; 
    mv "$file" "${date_str}_${alphachars}.${ext}"; 
done 

С рекурсивным find:

#!/usr/bin/env bash 
find . -maxdepth 3 -type f -name '*.txt' | while read -r file; do 
    filename=${file##*/}; 
    dir=${file%/*}; 
    str_date="$(grep -oP '\(\K[^\)]+' <<< "$filename")"; 
    date_str=$(date -d"$str_date" +%y%m%d); 
    alphachars="${filename/ (*/}"; 
    ext="${filename##*.}"; 
    mv "${file}" "${dir}/${date_str}_${alphachars}.${ext}"; 
done 
+0

Извините, но это не работает. Когда я запускаю это, оболочка печатает «использование: grep ...» и «use: date ...». Когда я попробовал 'date_str = $ (date -d" Dec.1, 2013 "+% y% m% d)' и 'echo $ {date_str}', он пуст. – Aminopterin