Это в подходе, который я часто люблю использовать.
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 \\`echo \1 \| md5sum \| cut -d' ' -f 1\\`.\2|" | sh -
Команда "ls" создает поток текстовых строк. Команда "sed" преобразует каждую строку с правилами сопоставления с образцом. Команда «sed» выводит команду «mv», которая затем передается через оболочку «sh» для выполнения. Параметры команды "mv" похожи на "mv oldfilename newfilename", которое переименовывает файл. Я создаю новое имя файла с помощью команды sed, которая принимает часть перед последней точкой и выводит ее на вход команды "md5sum", а затем берет только хеш из ее вывода.
Проходя через мой процесс, сначала перечислите файлы списка ('head -n 3', чтобы увидеть только первые 3 строки):
ls | head -n 3
1000-26092016.xml
1000-27092016.xml
12312-28092016.xml
Затем подумайте о преобразовании с помощью sed (еще не передавая сгенерированные команды через оболочку)
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 \1.\2|" | head -n 3
mv 1000-26092016.xml 1000-26092016.xml
mv 1000-27092016.xml 1000-27092016.xml
mv 12312-28092016.xml 12312-28092016.xml
Есть три модели соответствия:
^\(.*\) = match from start-of-line up to a dot
\. = matches a single dot
\([^\.]*\)$ = match 0-or-more non-dot chars from end of line
Я хочу использовать sed, чтобы заменить имя входного файла на «mv filename NEWfilename», но, поскольку я передаю команды через оболочку, я могу генерировать команды, которые получают md5sum, как это
echo "1000-26092016" | md5sum
55b18a6b0add4a318b0079e18512b4e8 -
чтобы получить только хэш
echo "1000-26092016" | md5sum | cut -d' ' -f 1
55b18a6b0add4a318b0079e18512b4e8
В оболочке Unix мы можем использовать операторы backtick (`some_command`) для запуска подкоманды, например,
echo "howdy date there"
howdy date there
echo "howdy `date` there"
howdy Fri Sep 15 18:39:00 IST 2017 there
Возвращаясь к команде mv, я хочу, чтобы sed выдавал «mv here there», где «there» заменяется командой backtick, чтобы получить md5sum. Строка внутри sed replace-string начинается следующим образом
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 `echo \1 | md5sum | cut -d' ' -f 1`.\2|" | head -n 3
mv 1000-26092016.xml b026324c6904b2a9cb4b88d6d61c81d1.xml
mv 1000-27092016.xml b026324c6904b2a9cb4b88d6d61c81d1.xml
mv 12312-28092016.xml b026324c6904b2a9cb4b88d6d61c81d1.xml
Но явно создает один и тот же хеш для каждого имени файла, так как команда backticked-запускается до того, как sed увидит строку. Чтобы остановить оболочку, выполняющую команду backtick, чтобы sed выдавал обратные черты, мы должны добавить косую черту (также к символу канала), и снова:
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 \`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2|" | head -n 3
mv 1000-26092016.xml `echo 1000-26092016 | md5sum | cut -d' ' -f 1`.xml
mv 1000-27092016.xml `echo 1000-27092016 | md5sum | cut -d' ' -f 1`.xml
mv 12312-28092016.xml `echo 12312-28092016 | md5sum | cut -d' ' -f 1`.xml
Выходные данные также требуют имен файлов в кавычках в случае пробелов, поэтому
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \"\1.\2\" \"\`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2\"|" | grep trick
mv "a trick€€ fíle nÁme.xml" "`echo a trick€€ fíle nÁme | md5sum | cut -d' ' -f 1`.xml"
Итак, давайте попробуем это, пропустив через оболочку:
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \"\1.\2\" \"\`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2\"|" | grep trick | sh -
Это сработало? Я полагаю:
echo "a trick€€ fíle nÁme" | md5sum
629db9c3071928ba0746f18444713b65 -
ls 629db9c3071928ba0746f18444713b65*
629db9c3071928ba0746f18444713b65.xml
Вот подход к перекрестной проверке; используйте параметр «ls» «-i» для вывода i-узла файловой системы unix (который не изменяется с «mv»):
ls -1i | sort -n > .before
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \"\1.\2\" \"\`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2\"|" | sh -
ls -1i | sort -n > .after
cut -d' ' -f 1 .before | while read I ; do echo "mv'd \"`grep ${I} .before`\" to \"`grep ${I} .after`\"" | sed "s| *$I *||g" ; done | head -n 3
mv'd "1000-26092016.xml" to "55b18a6b0add4a318b0079e18512b4e8.xml"
mv'd "1000-27092016.xml" to "b1baa80d99d5edf85c8aeb98185dd440.xml"
mv'd "12312-28092016.xml" to "2b2d692bd047b64c99f7b9161349d430.xml"
Или, используя команду "paste" (пакет 'coreutils')
paste .before .after | head -n 3
36703389 1000-26092016.xml 36703389 55b18a6b0add4a318b0079e18512b4e8.xml
36703390 1000-27092016.xml 36703390 b1baa80d99d5edf85c8aeb98185dd440.xml
36703391 12312-28092016.xml 36703391 2b2d692bd047b64c99f7b9161349d430.xml