命令与征服
by Chunhao
首先,这篇日志和技术有关,应该用英文写的,但里面夹杂了一些中文的元素,就写成中文了。
这个题目,作为游戏的名字就是“命令与征服”,作为Full Circle中文杂志的一个栏目名,就是“决胜命令行”。
人们总在做关于图形界面与命令行的争论,其实,二者各有优缺点。图形界面总能给人一种直观的感受,在一定程度上提高工作效率。但是,任何事都有它的局限性。如果画一个圆,里面的空间代表图形界面所擅长的工作,那么,这个圆环外面的整个空间都应该属于命令行!
命令行也有它的局限性,用手敲命令的时间有时并不一定比把鼠标移到某个菜单并点一下快。而且,尤其是对于非英语国家的人来说,了解那么多的命令和参数并不是一件容易的事情,尽管man命令可以帮助我们很多。
命令行的一个杀手应用就是批处理。如果你需要对几十个,甚至几百个文件进行类似的操作,摆在你面前的有三条路:1. 等专门的软件被写出来。2. 自己纯手工对这几百个文件处理。3.动手写个脚本。
在Linux世界,如果你要完成一项工作,有三条法则:
- 如果有现成的软件,使用它。
- 如果需要使用几个软件来完成,用管道或其他东西把他们连接起来。
- 否则,自己写程序完成它。
使用命令行,使用脚本,应该是介于第二条和第三条之间。脚本是用于把几个程序连接起来的工具,当然,也算是自己写的一个程序。
在批处理中,我们可以通过脚本,通过定义的一些变量,甚至一些循环、判断语句来很轻松地完成工作。当然,这一些的基础就是命令行,脚本很难通过图形界面和其他程序交互。当然,也有一些在命令行中生成GUI的工具,例如zenity。
大概半年前,我做史记的电子书。其中,一个文件夹下的文件是这样的:
001.txt 002.txt 003.txt ... 130.txt
文件的开头是这样的:
史记
史记卷一 五帝本纪 第一*集解凡是徐氏义,称徐姓名以别之。余者悉是骃注解,并集觽家义。索隐纪者,记
也。本其事而记之,故曰本纪。又纪,理也,丝缕有纪。而帝王书称纪者,言为后代纲
…
我要作的就是把每个文件的文件名都改成这样的:
1_卷一五帝本纪第一.txt
在社区牛人们的帮助下,最终写出了如下脚本:
#!/bin/sh
for i in *.txt; do
f=${i%.*}
t=`head -n 2 $i | tail -n 1 | awk '{print substr($1,3,length($1)-1)}'`
cp $i ./tt/$f$t.txt
echo $i
done
当然,这是是个初步的脚本,以后还设计到全角半角空格的问题,文件编码等问题,就都不难解决了。
本人对相声很感兴趣,发现学院一个教授楼学庆的网页(校外可能无法访问)有几百段相声。就索性都抓下来了。但他的文件名都是1.wma 2.wma 3.wma之类的,很难知道那个文件是那段。于是索性把他的网页也抓下来了。每次先打开那个网页,然后选相应的相声听。
但这样太烦了,我总是想用Rhythmbox来管理我的音乐,这样就可以很好的利用艺术家和专辑来分类了。要做到这一点就意味着:1. 我必须把所有的wma转化成mp3,这样方便放到Mp3播放器上。2.必须把所有的“1.wma”都改成”八大改行(郭德纲\张文顺).mp3″这样的名字。3.必须对每个文件都加上tag。顺便说一点,一共有331个文件。
整个方法我构思了很久,格式转换我是借助了一个叫convertAudioFile的脚本。用到了mplayer和lame。加标签是用到了id3tag。
改文件名比较复杂,段子的名字和艺术家都在html文件里放着,我必须要根据原来的文件名从html中找到段子的名称和艺术家,然后再改名字。从html中分析我用到了Python,因为python有很好的分析html的库。我不会python,也只能现学现用。当时找了一个用python分析html的例子(现在怎么也找不到链接了,抱歉),就在上面改了改。居然能用了:
#!/usr/bin/python
# coding=utf-8
import sys
import urllib
import HTMLParser
import re
if len(sys.argv) < 3:
print 'options: [-n/-a] filename\n';
quit();
for i in sys.argv[1:]:
if i == '-n':
outputContent = 2;
elif i == '-a':
outputContent = 3;
elif i == sys.argv[2]:
inputFileName = i;
else:
print 'invalid option';
quit();
class CustomParser(HTMLParser.HTMLParser):
selected = ('table', 'h1', 'font', 'ul', 'li', 'tr', 'td', 'a')
def reset(self):
HTMLParser.HTMLParser.reset(self)
self._level_stack = []
def handle_starttag(self, tag, attrs):
if tag in CustomParser.selected:
self._level_stack.append(tag)
if "/".join(self._level_stack) == 'table/tr/td/a':
global fileName;
fileName = attrs[0][1];
def handle_endtag(self, tag):
if self._level_stack \
and tag in CustomParser.selected \
and tag == self._level_stack[-1]:
self._level_stack.pop()
def handle_data(self, data):
if "/".join(self._level_stack) == 'table/tr/td/a':
if outputContent == 2 and inputFileName == fileName:
print data.lstrip('1234567890').replace('/', '\\').encode('utf-8');
p = re.compile(u'\(.*\)');
m = p.search(data);
if m and outputContent == 3 and inputFileName == fileName:
print m.group().strip('\(\)').replace(u'、', '\\').replace('/', '\\').encode('utf-8');
content = unicode(urllib.urlopen('project/index.html', None).read(), 'utf8')
parser = CustomParser()
parser.feed(content)
parser.close()
网页的一部分是这样的:
<tr><td><a href="xiangsheng/1.wma">1八大改行(郭德纲/张文顺)</a></td> <td><a href="xiangsheng/2.wma">2论50年相声之现状(郭德纲/张文顺)</a></td> <td><a href="xiangsheng/3.wma">3大保镖(郭德纲/于谦)</a></td> <td><a href="xiangsheng/4.wma">4寿比南山(郭德纲/于谦)</a></td> <td><a href="xiangsheng/5.wma">5八猫图(郭德纲/于谦)</a></td></tr>
下面是脚本:
#!/bin/sh
num=`ls -l xiangsheng | wc -l`
cnt=1
for wma_file in xiangsheng/*; do
if [ -f $wma_file ]; then
echo $cnt/$num
wma_artist=`./project/parser.py -a $wma_file`
wma_name=`./project/parser.py -n $wma_file`
wma_base_name=`basename $wma_file`
temp_file="temp/"`echo "$wma_base_name" | sed 's/\.\w*$/'.wav'/'`
out_temp_file="output/"`echo "$wma_base_name" | sed 's/\.\w*$/'.mp3'/'`
out_file="output/$wma_name"".mp3"
mplayer -ao pcm:file="$temp_file" "$wma_file"
lame -m auto --preset phone "$temp_file" "$out_temp_file"
mv "$out_temp_file" "$out_file"
id3tag -a"$wma_artist" -s"$wma_name" "$out_file"
rm "$temp_file"
fi
cnt=`expr $cnt + 1`
echo "\n##############################################3\n"
done
写得丑陋了点,也没有注释。大牛对此当然是不以为意了。
运行脚本,然后过了2个多小时,所有的转换都搞定了。慢慢欣赏相声…
另:今天晚上收到宋波的短信,他今天就要远赴阿尔及利亚去支援第三世界人民建设了。想起我们以前经常在一起说笑打闹,现在突然有最少7年见不到了,感觉有点凄凉。祝他在遥远的阿拉伯国家一切顺利,生活安逸!