我经常喜欢使用这种方法。
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”仅显示前三行):
ls | head -n 3
1000-26092016.xml
1000-27092016.xml
12312-28092016.xml
然后考虑使用sed进行转换(尚未通过shell传递任何生成的命令)
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文件名NEWfilename”,但是当我通过外壳管道命令时,我可以生成获取md5sum的命令,如下所示
echo "1000-26092016" | md5sum
55b18a6b0add4a318b0079e18512b4e8 -
只是散列
echo "1000-26092016" | md5sum | cut -d' ' -f 1
55b18a6b0add4a318b0079e18512b4e8
在unix shell中,我们可以使用反引号运算符(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 here”,用“ 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
但是很显然,每个文件名都使用相同的哈希,因为在sed看到字符串之前运行了backticked-command。要停止运行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”输出unix文件系统的i节点(不会随“ 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"
或者,使用“粘贴”命令(“ 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