<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Soul Of Free Loop &#187; shell</title>
	<atom:link href="https://zohead.com/archives/category/technology/shells/feed" rel="self" type="application/rss+xml" />
	<link>https://zohead.com</link>
	<description>Uranus Zhou&#039;s Blog</description>
	<lastBuildDate>Sat, 19 Jul 2025 15:42:46 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.8</generator>
	<item>
		<title>Linux运行dd时得到进度和速度</title>
		<link>https://zohead.com/archives/dd-progress-speed/</link>
		<comments>https://zohead.com/archives/dd-progress-speed/#comments</comments>
		<pubDate>Tue, 03 Jun 2014 15:53:28 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[dd]]></category>
		<category><![CDATA[lsof]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[信号]]></category>
		<category><![CDATA[进度]]></category>
		<category><![CDATA[速度]]></category>

		<guid isPermaLink="false">http://zohead.com/?p=716</guid>
		<description><![CDATA[本文同步自（最佳显示效果请点击）：https://zohead.com/archives/dd-progress-speed/ 我们常在 Linux 系统中使用 dd 命令做文件或设备的读取和写入操作，只是 dd 对读写进度和速度显示不是实时的，下面以两个磁盘设备之间的备份为例说明两种如何在 dd 命令运行过程中得到进度和速度的方法。 1、通过 dd 的信号得到进度和速度： 新的 Linux 系统中的 dd 命令支持在运行过程中接收 SIGUSR1 用户信号并显示当前实际读写了多少数据以及统计的平均速度是多少。 假设测试的是从 /dev/sdc 设备拷贝 360GB 的数据到 /dev/sdb [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>本文同步自（最佳显示效果请点击）：<a href="https://zohead.com/archives/dd-progress-speed/" target="_blank">https://zohead.com/archives/dd-progress-speed/</a></p>
<p>我们常在 Linux 系统中使用 dd 命令做文件或设备的读取和写入操作，只是 dd 对读写进度和速度显示不是实时的，下面以两个磁盘设备之间的备份为例说明两种如何在 dd 命令运行过程中得到进度和速度的方法。</p>
<p>1、通过 dd 的信号得到进度和速度：</p>
<p>新的 Linux 系统中的 dd 命令支持在运行过程中接收 SIGUSR1 用户信号并显示当前实际读写了多少数据以及统计的平均速度是多少。</p>
<p>假设测试的是从 /dev/sdc 设备拷贝 360GB 的数据到 /dev/sdb 裸设备中：</p>
<p><pre class="brush: bash; title: ; notranslate">
dd if=/dev/sdc of=/dev/sdb bs=1024k count=360000
</pre>
</p>
<p>然后切换到另一个 shell 中查看 dd 的 PID，并发送 SIGUSR1 信号：</p>
<p><pre class="brush: bash; title: ; notranslate">
~ # ps ax | grep dd
    2 ?        S      0:00 [kthreadd]
 5520 pts/1    D+     0:01 dd if=/dev/sdc of=/dev/sdb bs=1024k count=360000
 5534 pts/0    R+     0:00 grep dd
~ #
~ # kill -USR1 5520
~ # sleep 30
~ # kill -USR1 5520
</pre>
</p>
<p>再次切换到 dd 命令运行的 shell 上，就可以看到产生的两个 dd 命令的进度和速度输出，此时 dd 命令仍在运行中：</p>
<p><pre class="brush: bash; title: ; notranslate">
3226+0 records in
3225+0 records out
3381657600 bytes (3.4 GB) copied, 28.6073 s, 118 MB/s

6538+0 records in
6537+0 records out
6854541312 bytes (6.9 GB) copied, 58.0373 s, 118 MB/s
</pre>
</p>
<p>通过 SIGUSR1 得到的输出中显示是已拷贝的字节数、花费的时间和平均速度。</p>
<p>2、通过 lsof 命令得到进度和速度：</p>
<p>对于不支持 SIGUSR1 信号的 dd 命令或者其它系统来说，我们也可以使用 lsof 命令间接的来得到 dd 的进度和速度。</p>
<p>首先运行同样的拷贝硬盘的 dd 命令，检查 dd 命令的 PID，然后就可以使用 lsof 命令的 -p 选项指定 PID 查看 dd 命令打开的所有句柄：</p>
<p><pre class="brush: bash; title: ; notranslate">
~ # ps ax | grep dd
    2 ?        S      0:00 [kthreadd]
 4420 pts/0    D+     4:29 dd if /dev/sdc of /dev/sdb bs 1024k count 360000
 4987 pts/1    S+     0:00 grep dd

~ # lsof -p 4420
COMMAND  PID USER   FD      TYPE DEVICE     SIZE/OFF  NODE NAME
dd      4420 root  cwd       DIR  253,0         1024     2 /
dd      4420 root  rtd       DIR  253,0         1024     2 /
dd      4420 root  txt   unknown                           /proc/4420/exe
dd      4420 root  mem       REG  253,0       139336 58494 /lib64/ld-2.12.so
dd      4420 root  mem       REG  253,0        17816 38359 /lib64/libdl-2.12.so
dd      4420 root  mem       REG  253,0      1635256 38319 /lib64/libc-2.12.so
dd      4420 root  mem       REG  253,0       542112 58483 /lib64/libm-2.12.so
dd      4420 root  mem       REG  253,0        13760 58547 /lib64/libpam_misc.so.0.82.0
dd      4420 root  mem       REG  253,0        95016 58477 /lib64/libaudit.so.1.0.0
dd      4420 root  mem       REG  253,0        55280 38331 /lib64/libpam.so.0.82.2
dd      4420 root  mem       REG  253,0       387880 38325 /lib64/libfreebl3.so
dd      4420 root  mem       REG  253,0        38256 58471 /lib64/libcrypt-2.12.so
dd      4420 root    0r      BLK   8,32 0x3814900000  1125 /dev/sdc
dd      4420 root    1w      BLK   8,16 0x3814900000  1154 /dev/sdb
dd      4420 root    2u      CHR  136,0          0t0     3 /dev/pts/0
</pre>
</p>
<p>从上面的 lsof 输出可以看到，NAME 列出的有 dd 命令打开的 /dev/sdc 和 /dev/sdb 两个设备句柄，SIZE/OFF 列出的就是这两个句柄对应的文件大小和偏移量，由于设备句柄没有直接的文件大小，这里只显示了偏移量（从 0 字节开始，单位为字节，16 进制形式显示）。</p>
<p>这样我们可以直接计算出 dd 命令的进度（这里是直接以 360GB 的数据量来计算的，实际使用时需要修改，并且需要考虑到初始时是否有偏移量等问题）：</p>
<p><pre class="brush: bash; title: ; notranslate">
~ # lsof -p 4420 | gawk '{if ($NF==&quot;/dev/sdc&quot;) {print strtonum($(NF-2))*100/(360000*1048576)&quot; %&quot;;}}'
88.5208 %
</pre>
</p>
<p>上面的 88.5208% 就是 dd 的进度，同样我们使用延时计算的方法可以得到 dd 的当前实时速度：</p>
<p><pre class="brush: bash; title: ; notranslate">
~ # (lsof -p 4420 &amp;&amp; sleep 5 &amp;&amp; lsof -p 4420) | gawk '{if ($NF==&quot;/dev/sdc&quot;) {printf strtonum($(NF-2))&quot; &quot;;}}' | gawk '{print ($2-$1)/1048576/5;}'
96.2
</pre>
</p>
<p>这里采取间隔 5 秒钟调用一次 lsof 命令，然后使用 gawk 命令截取 lsof 输出中的偏移量并计算速度，实际速度以 MB/s 形式进行显示。</p>
<p>本文只是针对 dd 命令专门写的得到进度和速度的方法，相对而言第一种方法比较简单，而第二种方法可以做到不依赖 dd 命令的版本而且可以实时统计当前的实际速度，实际使用时有任何问题欢迎提出指正哦。</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/dd-progress-speed/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cygwin环境中调用VBScript的权限问题</title>
		<link>https://zohead.com/archives/cygwin-vbscript-permission/</link>
		<comments>https://zohead.com/archives/cygwin-vbscript-permission/#comments</comments>
		<pubDate>Sun, 01 Dec 2013 14:41:02 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[shell]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[Bash]]></category>
		<category><![CDATA[cygwin]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[MSYS]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[VBScript]]></category>
		<category><![CDATA[权限]]></category>

		<guid isPermaLink="false">http://zohead.com/?p=636</guid>
		<description><![CDATA[本文同步自（最佳显示效果请点击）：https://zohead.com/archives/cygwin-vbscript-permission/ 之前因为一个项目需求，需要在 Windows 上使用 Bash 脚本运行 Windows 上的程序，因此想到在 Cygwin 的 Bash 里实现（好吧，这确实比较令人蛋疼）。运行 Cygwin 中的 bash.exe 调用脚本，并启动另一个 VBScript 脚本来对一个 Excel 文件进行修改处理（使用 Windows 的原因了）。 刚开始通过 cscript.exe 命令在 Windows 自带的命令提示符中运行 VBScript 还比较顺便 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>本文同步自（最佳显示效果请点击）：<a href="https://zohead.com/archives/cygwin-vbscript-permission/" target="_blank">https://zohead.com/archives/cygwin-vbscript-permission/</a></p>
<p>之前因为一个项目需求，需要在 Windows 上使用 Bash 脚本运行 Windows 上的程序，因此想到在 Cygwin 的 Bash 里实现（好吧，这确实比较令人蛋疼）。运行 Cygwin 中的 bash.exe 调用脚本，并启动另一个 VBScript 脚本来对一个 Excel 文件进行修改处理（使用 Windows 的原因了）。</p>
<p>刚开始通过 cscript.exe 命令在 Windows 自带的命令提示符中运行 VBScript 还比较顺便，能顺利打开 Excel 文件并处理成功。但通过 Cygwin 的 Bash 脚本运行之后却老是在 VBScript 的打开 Excel 文件的地方提示找不到文件打开失败，顿时非常困惑。</p>
<p>Cygwin 的 Bash 脚本例子如下，test.sh 为 Bash 脚本程序，xxx.vbs 为处理 Excel 文件的 VBScript 脚本程序，运行 VBScript 脚本前需要先读取输入并传给 VBScript 脚本作为参数：</p>
<pre class="brush: bash; title: test.sh; notranslate">
#!./bash
echo &quot;Test script...&quot;
read TESTVAL

# xxx do something xxx

read TESTLEN
echo &quot;Require length: $TESTLEN&quot;

cscript //Nologo xxx.vbs $TESTVAL

# xxx do something else xxx

read TESTEND
echo &quot;....&quot;
</pre>
<p>初步考虑是 Cygwin 开启的 shell 权限不足，为解决问题，便尝试了各种方法：</p>
<ul>
<li>建立快捷方式设置以管理员方式运行，问题依旧；</li>
<li>把 Cygwin Bash shell 换为 MSYS 的，还是同样的报错；</li>
<li>通过 runas 命令以指定用户身份运行 cscript.exe VBScript 脚本，依旧。</li>
</ul>
<p>但非常奇怪的是，我手工运行 Cygwin bash.exe 开启一个终端，然后在终端中运行 cscript 调用 VBScript 结果却又一切正常。</p>
<p>为此不得不又把目光转移到 Bash 脚本代码中，除了刚开始有两个 read 读取输入和 echo 输出操作外，并没有什么特殊的操作。实在找不到办法，就把 cscript 操作放在脚本最前面（使用固定参数，不通过读取输入的方式传入），再运行 test.sh 却惊奇的发现可以正常工作了。有点头绪了，由于运行 VBScript 必须从当前 Bash 脚本中传入参数，因此尝试着把第二个暂时不是特别必要的 read 和 echo 操作注释掉（第 7 和 第 8 行），也工作正常。</p>
<p>再经过反复测试发现 Cygwin 启动的 Bash 在运行了两次 read 操作之后再调用 VBScript 脚本就会出现权限不对的问题，只 read 一次或者完全不做 read 读取输入操作（cscript 命令放在最开始）都不会有问题。</p>
<p>现在也实在没明白两次 read 读取输入操作会导致什么系统环境不一样才使 VBScript 运行失败，Google 之后有朋友也遇到这种问题但没有正确的解答，可能这种改 read 方式并不彻底，但目前也算权宜之道了 ^_^。</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/cygwin-vbscript-permission/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EasyMoney财务数据迁移到随手记的流程</title>
		<link>https://zohead.com/archives/easymoney-to-feidee/</link>
		<comments>https://zohead.com/archives/easymoney-to-feidee/#comments</comments>
		<pubDate>Wed, 21 Aug 2013 16:33:01 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[shell]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[财务]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[CSV]]></category>
		<category><![CDATA[EasyMoney]]></category>
		<category><![CDATA[easymoney2feidee]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[同步]]></category>
		<category><![CDATA[报表]]></category>
		<category><![CDATA[脚本]]></category>
		<category><![CDATA[迁移]]></category>
		<category><![CDATA[随手记]]></category>

		<guid isPermaLink="false">http://zohead.com/?p=484</guid>
		<description><![CDATA[关于 EasyMoney 记账软件 之前在 Android 手机一直都用一个比较小巧的记账软件 Handy EasyMoney（轻松理财） 来记录管理平时的理财开销等数据，虽然这个 App 也比较流畅好用，但用到后来越来越发现 EasyMoney 的缺点： 只支持 Android 平台，不支持 iOS、Windows 等平台； 完全不支持网络，没有同步、Web 管理等操作，更别想实现全平台同步等目标了； 老版本导出的数据有可能导入不了新版本，有点不保险； 条件查询、报表管理功能还比较薄弱； 采用私有的数据格式，导出只能再选择 CSV 格式导出，不方便迁移到其它软件； 不支持导入其它财务软件的数 [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2>关于 EasyMoney 记账软件</h2>
<p>之前在 Android 手机一直都用一个比较小巧的记账软件 Handy EasyMoney（轻松理财） 来记录管理平时的理财开销等数据，虽然这个 App 也比较流畅好用，但用到后来越来越发现 EasyMoney 的缺点：</p>
<ul>
<li>只支持 Android 平台，不支持 iOS、Windows 等平台；</li>
<li>完全不支持网络，没有同步、Web 管理等操作，更别想实现全平台同步等目标了；</li>
<li>老版本导出的数据有可能导入不了新版本，有点不保险；</li>
<li>条件查询、报表管理功能还比较薄弱；</li>
<li>采用私有的数据格式，导出只能再选择 CSV 格式导出，不方便迁移到其它软件；</li>
<li>不支持导入其它财务软件的数据。</li>
</ul>
<p>而最近看到的随手记软件（官网：<a href="http://www.feidee.com/" target="_blank">http://www.feidee.com/</a>）则基本都解决了上面的问题，特别是全平台同步（不止主流的 Android、iPhone、iPad 等平台，连软件现在很稀少的 Windows Store 上都有随手记了）和强大的 Web 管理功能还是有比较深的印象。</p>
<p>最近想着能把数据从 EasyMoney 迁移到随手记，但由于 EasyMoney 并不是特别知名，随手记支持的数据导入方式并没有 EasyMoney，而我在 EasyMoney 上已经记了一年多的财务数据，如果手工导入是会疯掉的。因此稍研究了下 EasyMoney 的 CSV 导出数据格式和随手记的 Web 导入格式，写了一个脚本来自动实现数据转换，方便进行导入。</p>
<h2>EasyMoney 数据导入随手记</h2>
<p>下面以我现在使用的 Handy EasyMoney 1.6.3 汉化版本为例子说明如何将 EasyMoney 财务数据导入到随手记中，英文版的 EasyMoney 的方法需要稍做下改动，请注意下面的说明。</p>
<p>首先进入手机的 EasyMoney App，记下随手记里的各个账户的名称和初始余额，例如我的账户列表为（名称不可出错）：<strong>现金</strong>、<strong>信用卡</strong>、<strong>银行账户</strong>、<strong>支付宝</strong>。然后点击菜单中的“数据库工具”，选择“导出.CSV”，然后就可以选择不同的账户类型进行导出，建议将“字段分隔符”设置为“|”或者“Tab”，防止和财务数据中的信息冲突 ：</p>
<p><a href="https://zohead.com/wp-content/uploads/easymoney-export-csv.jpg"><img title="EasyMoney导出CSV数据" alt="EasyMoney导出CSV数据" src="https://zohead.com/wp-content/uploads/easymoney-export-csv.jpg" width="219" height="246" /></a></p>
<p>点击“导出”按钮就会在 SD 卡的 EasyMoney/csv_output 文件夹中产生对应的 CSV 文件，将 CSV 文件拷贝到 PC 中，可以用支持 UTF-8 的文本编辑器打开检查下，格式就像下面这样：</p>
<pre class="brush: plain; title: 现金_cny.csv; notranslate">
PAYEE_ITEM_DESC|CATEGORY|AMOUNT|STATUS|TRAN_DATE|REMARKS
&quot;上海汽车站&quot;|&quot;交通&quot;|-42.00|&quot;未清算&quot;|&quot;21 Aug 2013&quot;|&quot;回常熟汽车票&quot;|
&quot;常熟公交&quot;|&quot;交通&quot;|-1.00|&quot;未清算&quot;|&quot;21 Aug 2013&quot;|&quot;汽车南站回公司&quot;|
&quot;银环面馆&quot;|&quot;食品&quot;|-8.00|&quot;未清算&quot;|&quot;21 Aug 2013&quot;|&quot;午餐&quot;|
&quot;华兴便利&quot;|&quot;食品&quot;|-1.50|&quot;未清算&quot;|&quot;21 Aug 2013&quot;|&quot;中午雪糕&quot;|
&quot;安徽大排档&quot;|&quot;食品&quot;|-8.00|&quot;未清算&quot;|&quot;21 Aug 2013&quot;|&quot;晚餐&quot;|
&quot;华联超市&quot;|&quot;购物&quot;|-13.60|&quot;未清算&quot;|&quot;21 Aug 2013&quot;|&quot;瑞士卷、山楂、雪碧、牙膏&quot;|
</pre>
<p>下面先访问<a href="http://www.feidee.com/" target="_blank">随手记官方网站</a>，进入 “我的账本”，点击 “账户” 标签，向随手记的账户列表预先添加好需要的账户以备导入，账户列表里的账户名称最好与 EasyMoney 中的账户名称一致，这样批量导入数据比较方便（可以等导入完成之后修改账户名称的）。</p>
<p>例如如下图所示，我把现金账户中的子账户名称改为与 EasyMoney 对应的名称：<strong>现金</strong>，并设置初始余额，将信用卡账户中的子账户名称改为：<strong>信用卡</strong>，将金融账户中的子账户名称改为：<strong>银行账户</strong>，并在虚拟账户中建立一个账户，名称为：<strong>支付宝</strong>。</p>
<p><a href="https://zohead.com/wp-content/uploads/efeidee-account-list.jpg"><img title="随手记账户列表" alt="随手记账户列表" src="https://zohead.com/wp-content/uploads/feidee-account-list.jpg" width="428" height="306" /></a></p>
<p>需注意的是 EasyMoney 中信用卡账户与普通账户没什么区别，初始余额表示信用卡的初始可用额度，例如 10000 元的信用卡初始余额为 8000 元；而在随手记中初始余额表示信用卡的负债数额，这样上面的情况就可以用随手记专门的“信用卡”功能模块，先设置信用卡可用额度为 10000 元，初始负载数额为 2000 元。</p>
<p>随后进入随手记 Web 版的 “记账” 标签，这时就有几条记录表示余额变更，此时需要将这几条记录的时间修改为 EasyMoney 中最早的记录时间之前，这样导入数据之后账户的余额就是正确的值。</p>
<p>下载导入数据用的随手记 Web 版 Excel 模板（点击 [<a href="http://money.feidee.com/u07/downloadDoc/template.xls" target="_blank">这里</a>] 下载），打开查看一下随手记的数据格式如下所示：</p>
<p><a href="https://zohead.com/wp-content/uploads/feidee-template.jpg"><img title="随手记数据格式" alt="随手记数据格式" src="https://zohead.com/wp-content/uploads/feidee-template.jpg" width="585" height="122" /></a></p>
<p>简单研究了随手记的 Excel 模板格式之后，我写了一个 Linux shell 环境（Windows 上也可以使用 Cygwin 等 shell 环境）下运行的 easymoney2feidee.sh 脚本来自动将 EasyMoney 导出的数据转换为随手记的数据格式。</p>
<p>你可以直接点击 [<a href="http://0paste.com/528.txt" target="_blank">这里</a>] 或 [<a href="http://paste.ubuntu.com/6010802/" target="_blank">这里</a>] 下载此脚本，脚本内容如下：</p>
<pre class="brush: bash; title: easymoney2feidee.sh; notranslate">
#!/bin/sh
if [ $# -lt 3 ]; then
echo &quot;Usage: $0 csv-file account-type out-file&quot;
exit
fi

EM_FILE=&quot;$1&quot;
EM_TYPE=&quot;$2&quot;
EM_OUT=&quot;$3&quot;

sed -i 's/\&quot;//g' $EM_FILE

gawk -F '|' -v ETYPE=&quot;$EM_TYPE&quot; 'BEGIN{
m = split(&quot;Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec&quot;, d, &quot;|&quot;)
for (o = 1; o &lt;= m; o++){
months[d[o]] = sprintf(&quot;%02d&quot;, o)
}
}
{
if (NR &gt; 1 &amp;&amp; $2 != &quot;转账 (转入)&quot;) {
OUT_TYPE = &quot;&quot;;
OUT_VAL = $3;
if ($2 == &quot;转账 (转出)&quot;) {
if (substr($1, 1, 13) == &quot;转入账户 &quot;) {
OUT_TYPE = substr($1, 14);
}
printf &quot;转账&quot;;
} else if ($3 &gt; 0) {
printf &quot;收入&quot;;
} else {
printf &quot;支出&quot;;
}
if ($3 &lt; 0) {
OUT_VAL = -OUT_VAL;
}
split($5, time, &quot; &quot;);
date = time[3]&quot; &quot;months[time[2]]&quot; &quot;time[1]&quot; 0 0 0&quot;
printf &quot;\t&quot;strftime(&quot;%Y-%m-%d&quot;, mktime(date));
if (length(OUT_TYPE) &lt;= 0) {
printf &quot;\t&quot;$2;
} else {
printf &quot;\t&quot;;
}
printf &quot;\t&quot;;
printf &quot;\t&quot;ETYPE;
printf &quot;\t&quot;OUT_TYPE;
printf &quot;\t&quot;OUT_VAL;
printf &quot;\t本人&quot;;
if (length(OUT_TYPE) &lt;= 0) {
printf &quot;\t&quot;$1;
} else {
printf &quot;\t&quot;;
}
printf &quot;\t&quot;;
printf &quot;\t&quot;$6&quot;\n&quot;;
}
}' $EM_FILE &gt; $EM_OUT
</pre>
<p>下面简单说明下脚本：</p>
<p>在 shell 下运行 easymoney2feidee.sh 脚本并传入 3 个参数，分别表示 EasyMoney CSV 文件名、CSV 文件对应的账户名称、输出文件名称。</p>
<p>如果你的 CSV 文件不是用 “|” 隔开的，请修改脚本第 13 行中的 “|” 分隔符。脚本首先会去掉 CSV 文件中的所有双引号方便处理数据，然后按分割符得到数据，并判断是否是 EasyMoney 的转账处理（转出需要分别记录本账户名称、转入的账户名称；如果是转入则不需要记录），先记录财务记录类型，然后将 EasyMoney 的日期（EasyMoney 只支持日期，没有细化到具体时间）转换为随手记的时间格式，记录商家、金额（EasyMoney 金额为正值表示收入，负值表示支出）等信息，最终以 Tab 隔开生成输出文件（Tab 隔开的文本复制到随手记 Excel 表格中时可以自动跨越列）。</p>
<p>需要注意的是此脚本处理的是汉化版的 EasyMoney 的数据，其中转账用的固定值为：<strong>转账 (转入)</strong>、<strong>转账 (转出)</strong>、<strong>转入账户</strong>，如果你使用的是英文原版的 EasyMoney App，那需要将脚本小做下修改。</p>
<p>例如我在 Cygwin 环境下运行脚本将 “现金” 账户的 CSV 文件转为随手记的数据：</p>
<p>./easymoney2feidee.sh <strong>现金_cny.csv</strong> <strong>现金</strong> <strong>现金.txt</strong></p>
<p>输出的文件即为：<strong>现金.txt</strong> 文件，使用文本编辑器打开 <strong>现金.txt</strong> 文件，并将所有内容复制到随手记的模板 Excel 文件中并保存，最终数据形式即符合随手记的要求了（检查下与 EasyMoney 的 CSV 数据是否相符）：</p>
<p><a href="https://zohead.com/wp-content/uploads/feidee-data.jpg"><img title="导入的随手记数据" alt="导入的随手记数据" src="https://zohead.com/wp-content/uploads/feidee-data.jpg" width="608" height="106" /></a></p>
<p>然后就可以到随手记的 “我的账本” 首页中选择 “导入导出” 并选择数据导入选项的 “随手记web版”，选择上面生成的 Excel 文件，点击 “上传数据” 等待片刻，随手记就能识别到数据，此时还需要最后一步选择分类数据和随手记账户：</p>
<p><a href="https://zohead.com/wp-content/uploads/feidee-import.jpg"><img title="导入随手记数据" alt="导入随手记数据" src="https://zohead.com/wp-content/uploads/feidee-import.jpg" width="614" height="381" /></a></p>
<p>如上图所示，仔细选择 EasyMoney 中的分类和随手记分类的对应关系，并选择导入的随手记账户，点击导入数据按钮，稍等几分钟数据就正确导入了（我的现金账户 2000 条数据导入花了 4 分钟左右），在随手记 Web 版的记账界面中可以查看到：</p>
<p><a href="https://zohead.com/wp-content/uploads/feidee-view-data.jpg"><img title="成功导入的数据" alt="成功导入的数据" src="https://zohead.com/wp-content/uploads/feidee-view-data.jpg" width="594" height="130" /></a></p>
<p>如果你发现刚才选择的分类有的条目不对应，完全可以借助随手记强大的条件查询功能先搜索到对应条目，然后使用批量修改功能统一进行修改，总之比 EasyMoney 的可用性好不少。</p>
<p>本文为个人总结经验所得，所写的脚本并不适合所有的情况，因此使用中有任何问题欢迎提出指正哦，玩的开心~~~ ^_^</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/easymoney-to-feidee/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>sed命令临时文件空间占用的问题</title>
		<link>https://zohead.com/archives/sed-space-usage/</link>
		<comments>https://zohead.com/archives/sed-space-usage/#comments</comments>
		<pubDate>Sat, 08 Jun 2013 18:56:18 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[shell]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[sed]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[参数]]></category>
		<category><![CDATA[命令]]></category>
		<category><![CDATA[替换]]></category>
		<category><![CDATA[监控]]></category>

		<guid isPermaLink="false">http://zohead.com/?p=428</guid>
		<description><![CDATA[本文同步自（最佳显示效果请点击）：https://zohead.com/archives/sed-space-usage/ sed 是 Unix(Linux) 系统中经常使用的编辑命令，常被用来修改编辑替换文件中的数据。我在平时也经常用到 sed 命令，最近遇到一个比较奇怪的空间占用的问题： 在类似嵌入式的使用环境中有一个比较大的文本文件，由于环境所限，此文件所占用的空间也有限制，假设最多为 20MB，超过 20MB 将导致系统中其它文件没有空间，后续修改其它文件会报：Not enough space 错误。 因此我需要定期对这个文件大小进行监控，如果超过 20MB 那就用 sed 命令删除其 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>本文同步自（最佳显示效果请点击）：<a href="https://zohead.com/archives/sed-space-usage/" target="_blank">https://zohead.com/archives/sed-space-usage/</a></p>
<p>sed 是 Unix(Linux) 系统中经常使用的编辑命令，常被用来修改编辑替换文件中的数据。我在平时也经常用到 sed 命令，最近遇到一个比较奇怪的空间占用的问题：</p>
<p>在类似嵌入式的使用环境中有一个比较大的文本文件，由于环境所限，此文件所占用的空间也有限制，假设最多为 20MB，超过 20MB 将导致系统中其它文件没有空间，后续修改其它文件会报：Not enough space 错误。</p>
<p>因此我需要定期对这个文件大小进行监控，如果超过 20MB 那就用 sed 命令删除其中的数据，每次删除 5000 - 10000 行直至文件大小不超过 18MB（留一定的余量）。</p>
<p>定时监控的脚本操作就类似这样（假设 <strong>/var/myfile</strong> 为监控文件）：</p>
<pre class="brush: bash; title: ; notranslate">
while [ 1 ]; do
   # get file size
   FILE_SIZE=`wc -c &lt; /var/myfile`
   if [ $FILE_SIZE -le 18874368 ]; then
      break
   fi
   sed -i '/1,5000d' /var/myfile
   sleep 600
done
</pre>
<p>上面的脚本会每 10 分钟检测一次，如果超过 18MB 就用 sed 的 “-i” 参数自动删除文件开头的 5000 行，这看起来是能起到监控的作用的，但实际运行中，<strong>/var/myfile</strong> 的空间并没有被释放，而且系统被完全占满了，同时 /var 目录下还产生了一堆文件（有几百个之多，没有完全列出来）：</p>
<pre class="brush: bash; title: ; notranslate">
[root@server ~]# ls /var
myfile sedBu2rt9 sed4l4DpD sedXoiew0 sed09rwbn sedHc0987
...
</pre>
<p>这明显就是 sed 命令产生的临时文件了，但为什么没有自动删除的，而且产生了这么多个。</p>
<p>经过详细查询 sed 命令的帮助信息，终于知道了原因：</p>
<p>sed 的 “-i” 参数表示 edit files in place，熟悉 sed 命令的朋友应该知道不加 “-i” 参数时对文件的修改操作是直接写到 stdout 标准输出并不修改文件的。</p>
<p>sed 的 “-i” 参数做的操作就是将原先修改的 stdout 输出先保存成一个临时文件，并且临时文件与原始的文件在同一目录下（通过 mktemp 之类的方法生成，也就是上面看到的 sedXXXXXX 这种形式的临时文件，假设为：<strong>/var/sedBu2rt9</strong>），完成之后再将临时文件重命名覆盖为原始的文件（相当于：<strong>mv /var/sedBu2rt9 /var/myfile</strong> 操作），这样临时文件就消失了，也可以看出 “-i” 参数并不是直接修改 /var/myfile 文件本身。</p>
<p>在正常情况下，上面的流程是没问题的，但当系统空间不够这种极端情况时，sed 第一步将 stdout 输出保存到临时文件就会失败（空间已经不足），后续的重命名覆盖为原始的文件当然并不会做，但是悲剧的是 sed 在这种失败情况下连产生的错误临时文件也不删除，结果空间不足的情况会更加严重（第一步可能写了一部分数据到临时文件），而且会留下来一堆没用的临时文件。</p>
<p>另外 sed 命令的 “-i” 参数还有一个潜在的问题：</p>
<p>从上面的流程我们可以看出，通过 “-i” 参数修改文件之后，源文件的 inode 已经发生了变化（不是真正原始的文件了），如果此前有其它程序已经打开了该文件，后续读取会失败，而且这种情况下由于原始的 inode 还在被使用，虽然 inode 已经无效了，但对文件系统的占用并没有被释放，因此像这种源文件同时被其它程序打开的情况下，还必须关闭重启此程序或者通知程序重新打开文件才能真正释放文件系统的空间。</p>
<p>因此对于 sed 的这种情况，我们可以通过其它的程序来修改文件，也可以单独开辟别的空间（例如 tmpfs 之类）先拷贝一份通过 sed 命令进行修改，然后再拷贝覆盖回源文件。</p>
<p>以上是根据个人实际使用中所遇到的情况总结出来的，有任何问题欢迎提出指正哦 ^_^</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/sed-space-usage/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Linux中拷贝目录跳过指定文件的方法</title>
		<link>https://zohead.com/archives/linux-copy-directory-ignore-files/</link>
		<comments>https://zohead.com/archives/linux-copy-directory-ignore-files/#comments</comments>
		<pubDate>Thu, 31 May 2012 16:30:44 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[Bash]]></category>
		<category><![CDATA[cp]]></category>
		<category><![CDATA[cpio]]></category>
		<category><![CDATA[find]]></category>
		<category><![CDATA[rsync]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[命令]]></category>
		<category><![CDATA[忽略]]></category>
		<category><![CDATA[拷贝]]></category>
		<category><![CDATA[目录]]></category>
		<category><![CDATA[跳过]]></category>

		<guid isPermaLink="false">http://zohead.com/?p=205</guid>
		<description><![CDATA[本文同步自（如浏览不正常请点击跳转）：https://zohead.com/archives/linux-copy-directory-ignore-files/ 近日在 Linux 环境中做版本迁移的时候遇到一个问题：需要将一个目录遍历拷贝到另一个目录中，但需要忽略其中的某些文件，由于目录中东西比较多，忽略的项也不好一一指定。普通的 cp 命令并没有排除某个文件或文件夹的参数，比较丑陋点可以 cp -r 拷贝完目录之后再去删除无用的，但如果做批量脚本操作就不爽了，经过实际试验之后暂时找到两个比较好的方法。 1、使用 rsync 进行拷贝： rsync 本来是文件同步备份的工具，相对于普通的  [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>本文同步自（如浏览不正常请点击跳转）：<a href="https://zohead.com/archives/linux-copy-directory-ignore-files/" target="_blank">https://zohead.com/archives/linux-copy-directory-ignore-files/</a></p>
<p>近日在 Linux 环境中做版本迁移的时候遇到一个问题：需要将一个目录遍历拷贝到另一个目录中，但需要忽略其中的某些文件，由于目录中东西比较多，忽略的项也不好一一指定。普通的 cp 命令并没有排除某个文件或文件夹的参数，比较丑陋点可以 cp -r 拷贝完目录之后再去删除无用的，但如果做批量脚本操作就不爽了，经过实际试验之后暂时找到两个比较好的方法。</p>
<p><strong>1、使用 rsync 进行拷贝：</strong></p>
<p>rsync 本来是文件同步备份的工具，相对于普通的 cp 命令，rsync 在控制方面就强多了，而且 rsync 对遍历目录也支持，有 --exclude 参数可以忽略指定的文件或文件夹。</p>
<p><em><span style="color: #008000;">rsync -vaP --exclude=".*" --exclude="Makefile" dir1 /home/dir2</span></em></p>
<p>如上面演示的就可以排除掉隐藏文件和 Makefile 文件，-a 参数已经包含遍历处理参数 -r。</p>
<p><strong>2、使用 find 加 cpio 进行拷贝：</strong></p>
<p>备注：此方法来自 Advanced Bash-Scripting Guide，需要了解的童鞋自己去参考了。</p>
<p>用过 find 的童鞋都知道，find 对文件的过滤那是非常强大的，配合 cpio 来进行目录的遍历拷贝就可以实现过滤指定的文件或文件夹，当然也可以做到只备份特定的文件或文件夹，你可以用 find 的各种过滤参数达到拷贝哪天的文件，拷贝近期更改的文件等特殊效果，而且 find 支持正则表达式，这种方式想比第一种使用 rsync 跳过文件的方式更加灵活，因此非常推荐使用此方式进行目录拷贝。</p>
<p><em><span style="color: #008000;">cd dir1<br />
find . -regextype posix-egrep -mindepth 1 ! -regex './(dev|tmp)($|/.*)' ! -name Makefile -a ! -name .svn | cpio -admvp /home/dir2<br />
</span></em></p>
<p>小解释下：</p>
<p>find 的 -regextype 参数指定正则表达式类型，posix-egrep 为 egrep 用的扩展正则表达式，-mindepth 使 find 的输出中不包括目录本身，-regex 参数指定过滤的文件的正则表达式，-regex 前面的感叹号表示跳过，'./(dev|tmp)($|/.*)' 这个正则表达式即表示跳过目录中的第一层 dev 和 tmp 目录以及下面所有的文件和文件夹，最后两个 -name 指定要跳过文件名为 Makefile 和 .svn 的文件，这样在备份版本库的时候非常有用。</p>
<p>cpio 命令将 find 的输出文件列表依次拷贝到 /home/dir2 目标目录中，-a 表示不更新文件的访问时间，-d 指定自动创建目录，-m 指定保留文件的修改时间，-p 指定 cpio 工作在 Copy-pass 模式，这是专门用来拷贝目录树的一种模式。</p>
<p>PS：如果有更加简单的方法，欢迎提出指正哦~~~ ^_^</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/linux-copy-directory-ignore-files/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
