Linux shell利用sed如何批量更改文件名详解
<p><span><strong>前言</strong></span></p>
<p>
本文主要给大家介绍了关于Linux shell用sed批量更改文件名的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。</p>
<p>
<span><strong>示例</strong></span></p>
<p>
<strong>去除特定字符</strong></p>
<p>
目标:将 2017-01-01.jpg、2018-01-01.jpg 改为 20170101.jpg、20180101.jpg</p>
<p>
方法:将所有 - 替换为空</p>
<div class="jb51code">
<div>
<div class="syntaxhighlighterbash" id="highlighter_756738">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
<div class="line number2 index1 alt1">
2</div>
<div class="line number3 index2 alt2">
3</div>
<div class="line number4 index3 alt1">
4</div>
<div class="line number5 index4 alt2">
5</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="bash keyword">for</code> <code class="bash functions">file</code> <code class="bash keyword">in</code> <code class="bash plain">`</code><code class="bash functions">ls</code> <code class="bash plain">| </code><code class="bash functions">grep</code> <code class="bash plain">.jpg`</code>
</div>
<div class="line number2 index1 alt1">
<code class="bash keyword">do</code>
</div>
<div class="line number3 index2 alt2">
<code class="bash spaces"> </code><code class="bash plain">newfile=`</code><code class="bash functions">echo</code> <code class="bash plain">$</code><code class="bash functions">file</code> <code class="bash plain">| </code><code class="bash functions">sed</code> <code class="bash string">'s/-//g'</code><code class="bash plain">`</code>
</div>
<div class="line number4 index3 alt1">
<code class="bash spaces"> </code><code class="bash functions">mv</code> <code class="bash plain">$</code><code class="bash functions">file</code> <code class="bash plain">$newfile</code>
</div>
<div class="line number5 index4 alt2">
<code class="bash keyword">done</code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
这里使用sed进行标准输出的字符串替换,其通用格式如下:</p>
<div class="jb51code">
<div>
<div class="syntaxhighlighterbash" id="highlighter_838339">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="bash plain">stdout | </code><code class="bash functions">sed</code> <code class="bash string">'s/pattern/replace/'</code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
上述示例中,在末尾添加g用于替换所有匹配项,而不仅仅替换第一个匹配项。</p>
<p>
<strong>中间插入字符</strong></p>
<p>
目标:将 book01.txt、paper02.txt 改为 book-01.txt、paper-02.txt</p>
<p>
方法:用分组匹配分别获取待插入位置两侧的字符串,再通过反向引用实现替换</p>
<div class="jb51code">
<div>
<div class="syntaxhighlighterbash" id="highlighter_403139">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
<div class="line number2 index1 alt1">
2</div>
<div class="line number3 index2 alt2">
3</div>
<div class="line number4 index3 alt1">
4</div>
<div class="line number5 index4 alt2">
5</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="bash keyword">for</code> <code class="bash functions">file</code> <code class="bash keyword">in</code> <code class="bash plain">`</code><code class="bash functions">ls</code> <code class="bash plain">| </code><code class="bash functions">grep</code> <code class="bash plain">.txt`</code>
</div>
<div class="line number2 index1 alt1">
<code class="bash keyword">do</code>
</div>
<div class="line number3 index2 alt2">
<code class="bash spaces"> </code><code class="bash plain">newfile=`</code><code class="bash functions">echo</code> <code class="bash plain">$</code><code class="bash functions">file</code> <code class="bash plain">| </code><code class="bash functions">sed</code> <code class="bash string">'s/\(\+\)\(\+\)/\1-\2/'</code><code class="bash plain">`</code>
</div>
<div class="line number4 index3 alt1">
<code class="bash spaces"> </code><code class="bash functions">mv</code> <code class="bash plain">$</code><code class="bash functions">file</code> <code class="bash plain">$newfile</code>
</div>
<div class="line number5 index4 alt2">
<code class="bash keyword">done</code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
<span><strong>分析</strong></span></p>
<p>
上述示例首先通过 ls 和 grep 命令得到待改名的文件列表,然后用 sed 命令进行字符串的替换,最后再使用 mv 命令来完成文件名的更改。</p>
<p>
获取待改名文件列表的方法有很多,可以通过 find 命令,也可以直接给出字符串,我们将在下文中提到。</p>
<p>
注意 for 循环后面的 <code>ls | grep .txt</code>,这条命令用两个反单引号括了起来,与 <code>$(ls | grep .txt) </code>的作用相同,被包围的字符串会被当作命令执行,然后返回字符串结果。</p>
<p>
<strong>文件名包含空格的解决方法</strong></p>
<p>
我们可以直接将文件列表写到 for 循环中,而不是通过命令来得到,例如:</p>
<div class="jb51code">
<div>
<div class="syntaxhighlighterbash" id="highlighter_851168">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
<div class="line number2 index1 alt1">
2</div>
<div class="line number3 index2 alt2">
3</div>
<div class="line number4 index3 alt1">
4</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="bash keyword">for</code> <code class="bash functions">file</code> <code class="bash keyword">in</code> <code class="bash string">"file1 file2 file3"</code>
</div>
<div class="line number2 index1 alt1">
<code class="bash keyword">do</code>
</div>
<div class="line number3 index2 alt2">
<code class="bash spaces"> </code><code class="bash plain">...</code>
</div>
<div class="line number4 index3 alt1">
<code class="bash keyword">done</code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
可以看到 for 循环是通过空格来分割字符串,因此如果待更改的文件名中包含空格的话,就会被拆分成多个文件名,从而出错。</p>
<p>
要解决这个问题,我们可以将 IFS(内部字段分隔符)设置为换行符 \n,这样一来,for 循环就会按行来获取变量的值,确保每次获取的确实是一个完整的文件名。</p>
<p>
设置 IFS 变量的命令需要放在 for 循环之前:</p>
<div class="jb51code">
<div>
<div class="syntaxhighlighterbash" id="highlighter_306719">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
<div class="line number2 index1 alt1">
2</div>
<div class="line number3 index2 alt2">
3</div>
<div class="line number4 index3 alt1">
4</div>
<div class="line number5 index4 alt2">
5</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="bash plain">IFS=$</code><code class="bash string">'\n'</code>
</div>
<div class="line number2 index1 alt1">
<code class="bash keyword">for</code> <code class="bash functions">file</code> <code class="bash keyword">in</code> <code class="bash plain">`</code><code class="bash functions">ls</code><code class="bash plain">`</code>
</div>
<div class="line number3 index2 alt2">
<code class="bash keyword">do</code>
</div>
<div class="line number4 index3 alt1">
<code class="bash spaces"> </code><code class="bash plain">...</code>
</div>
<div class="line number5 index4 alt2">
<code class="bash keyword">done</code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
也可以直接使用 while read 命令一次读取一行到变量 file 中:</p>
<div class="jb51code">
<div>
<div class="syntaxhighlighterbash" id="highlighter_382208">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
<div class="line number2 index1 alt1">
2</div>
<div class="line number3 index2 alt2">
3</div>
<div class="line number4 index3 alt1">
4</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="bash functions">ls</code> <code class="bash plain">| </code><code class="bash functions">grep</code> <code class="bash string">"*.txt"</code> <code class="bash plain">| </code><code class="bash keyword">while</code> <code class="bash functions">read</code> <code class="bash functions">file</code>
</div>
<div class="line number2 index1 alt1">
<code class="bash keyword">do</code>
</div>
<div class="line number3 index2 alt2">
<code class="bash spaces"> </code><code class="bash plain">...</code>
</div>
<div class="line number4 index3 alt1">
<code class="bash keyword">done</code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
<strong>使用 find 获取文件列表</strong></p>
<p>
之前的示例中,我们是通过 ls 命令来获取文件列表。该命令只能获取某个目录的文件,而且没法进行多种条件的筛选。</p>
<p>
而一说到文件的查找,不得不提到功能强大的 find 命令。该命令可以在多个层次的目录中查找文件,并能够设定诸如创建时间、文件大小、所有者等多种条件,查找起文件来特别方便灵活。</p>
<p>
用 find 命令来获取文件列表,再用 sed 命令配合正则表达式来修改文件名,这两个命令的结合几乎能完成所有常见的批量改名任务。</p>
<p>
例如,将所有大于1M,且后缀为txt或jpg的文件,由形如 book_20170101.txt、image_20170101.jpg 的文件改名为 20170101-book.txt、20170101-image.jpg,代码如下:</p>
<div class="jb51code">
<div>
<div class="syntaxhighlighterbash" id="highlighter_417203">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
<div class="line number2 index1 alt1">
2</div>
<div class="line number3 index2 alt2">
3</div>
<div class="line number4 index3 alt1">
4</div>
<div class="line number5 index4 alt2">
5</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="bash keyword">for</code> <code class="bash functions">file</code> <code class="bash keyword">in</code> <code class="bash plain">`</code><code class="bash functions">find</code> <code class="bash plain">. -size +1M -name </code><code class="bash string">"*_*.txt"</code> <code class="bash plain">-o -name </code><code class="bash string">"*_*.jpg"</code><code class="bash plain">`</code>
</div>
<div class="line number2 index1 alt1">
<code class="bash keyword">do</code>
</div>
<div class="line number3 index2 alt2">
<code class="bash spaces"> </code><code class="bash plain">newfile=`</code><code class="bash functions">echo</code> <code class="bash plain">$</code><code class="bash functions">file</code> <code class="bash plain">| </code><code class="bash functions">sed</code> <code class="bash string">'s/\(\+\)_\(\+\)./\2-\1./'</code><code class="bash plain">`</code>
</div>
<div class="line number4 index3 alt1">
<code class="bash spaces"> </code><code class="bash functions">mv</code> <code class="bash plain">$</code><code class="bash functions">file</code> <code class="bash plain">$newfile</code>
</div>
<div class="line number5 index4 alt2">
<code class="bash keyword">done</code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
有关 find 命令的更多用法,可以参考 http://www.jb51.net/article/217260.html</p>
<p>
<span><strong>总结</strong></span></p>
<p>
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。</p>
<p>
原文链接:http://www.codebelief.com/article/2017/09/linux-shell-rename-multiple-files-using-sed/</p>
頁:
[1]