<?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/tag/shell/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>Android使用Shell命令配合Tasker控制手机</title>
		<link>https://zohead.com/archives/tasker-shell/</link>
		<comments>https://zohead.com/archives/tasker-shell/#comments</comments>
		<pubDate>Tue, 13 Dec 2016 16:38:02 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[GPS]]></category>
		<category><![CDATA[NFC]]></category>
		<category><![CDATA[Secure Settings]]></category>
		<category><![CDATA[Shadowsocks]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[Tasker]]></category>
		<category><![CDATA[飞行模式]]></category>

		<guid isPermaLink="false">https://zohead.com/?p=1325</guid>
		<description><![CDATA[Secure Settings 对比 Shell 命令 去年我写过一篇 Android 使用 Trigger + Tasker 设定 NFC 标签 的文章，主要介绍怎么使用 Tasker 和 Trigger App 设定 Android 手机刷 NFC 标签时执行指定的操作。该文章中对于手机的 飞行模式 / GPS / NFC 等功能的控制操作都是通过 Secure Settings App 实现的。 不过可惜的是我的华硕 Zenfone2 手机 ROM 升级到 6.0 版本之后，Secure Settings App 就有很多功能不能正常工作了，而且由于开发者也基本不再维护该 App 也有差 [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2 id="secure-settings-对比-shell-命令">Secure Settings 对比 Shell 命令</h2>
<p>去年我写过一篇 <a href="https://zohead.com/archives/tasker-nfc/">Android 使用 Trigger + Tasker 设定 NFC 标签</a> 的文章，主要介绍怎么使用 <a href="https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm" target="_blank">Tasker</a> 和 <a href="https://play.google.com/store/apps/details?id=com.jwsoft.nfcactionlauncher" target="_blank">Trigger</a> App 设定 Android 手机刷 NFC 标签时执行指定的操作。该文章中对于手机的 飞行模式 / GPS / NFC 等功能的控制操作都是通过 <a href="https://play.google.com/store/apps/details?id=com.intangibleobject.securesettings.plugin" target="_blank">Secure Settings</a> App 实现的。</p>
<p>不过可惜的是我的华硕 Zenfone2 手机 ROM 升级到 6.0 版本之后，Secure Settings App 就有很多功能不能正常工作了，而且由于开发者也基本不再维护该 App 也有差不多两年没有任何更新。</p>
<p>最近看到 <a href="http://www.notenoughtech.com/tasker/tasker-run-shell-commands/" target="_blank">Best run shell commands in Tasker</a> 文章介绍  Tasker 的几个常用 Shell 命令控制移动数据、飞行模式等选项，使用 Tasker 自带的运行 Shell 命令功能相比 Secure Settings 插件也有一些好处：</p>
<ul>
<li>Tasker 直接支持运行 Shell 命令（新增 <strong>操作类别</strong> -&gt; <strong>代码</strong> -&gt; <strong>运行外壳</strong> 即可），不需要专门安装 Secure Settings 等第三方 App；</li>
<li>多数命令在手机 root 后就能正常工作，不像 Secure Settings 那样需要特别安装成系统 App；</li>
<li>Shell 命令失效需要替换时也比较灵活，直接改 Shell 命令行就可以。</li>
</ul>
<p>因此我还是卸载了 Secure Settings App，将原来文章里的所有 Tasker 任务的 Secure Settings 操作都以 Shell 命令进行替代。</p>
<h2 id="tasker-任务使用-shell-命令">Tasker 任务使用 Shell 命令</h2>
<h3 id="数据开关-运行-shadowsocks">数据开关 + 运行 Shadowsocks</h3>
<p>为实现以下目标：</p>
<ol>
<li>具有路由器翻墙的住处网络环境下自动关闭手机 Shadowsocks 和移动数据；</li>
<li>其它网络环境下都开启 Shadowsocks 手机翻墙；</li>
<li>任何 Wi-Fi 环境下关闭移动数据以省电；</li>
<li>离开任何 Wi-Fi 自动开启移动数据。</li>
</ol>
<p>为此我建了 4 个 Tasker 配置和任务（当然也可以更简单）：</p>
<ol>
<li>连接住处的 OpenWRT Wi-Fi（根据 Tasker 的 SSID 条件区分） <br />
关闭 Shadowsocks 和移动数据；</li>
<li>连接其它 Wi-Fi <br />
关闭移动数据；</li>
<li>离开任何 Wi-Fi <br />
开启移动数据；</li>
<li>离开住处 Wi-Fi <br />
开启 Shadowsocks。</li>
</ol>
<p>现在 Android 版本 Shadowsocks App 是自带 Tasker 插件支持的（操作类别里选 <strong>插件</strong> -&gt; <strong>影梭</strong> 即可），开启和关闭 Shadowsocks 配置非常简单。</p>
<p>移动数据开关可以分别用下面的命令（Tasker 运行外壳中需要启用 <strong>使用Root</strong> 选项）：</p>
<pre class="brush: bash; title: ; notranslate">
svc data enable
svc data disable
</pre>
<h3 id="控制飞行模式及-nfc">控制飞行模式及 NFC</h3>
<p>为了实现和之前文章里类似的目标：</p>
<ol>
<li>睡觉前刷 NFC 标签开启飞行模式；</li>
<li>打开 NFC（这样起来之后可以刷 NFC 标签）；</li>
<li>起来刷 NFC 标签关闭飞行模式。</li>
</ol>
<p>另外考虑最好只使用一个 NFC 标签就达到效果，这里我只建了一个 Tasker 任务包含 4 个操作：</p>
<ol>
<li>Tasker 操作类别中选 <strong>变量</strong> -&gt; <strong>变量设置</strong>，<code>%TMPAIR</code> 发往 <code>%AIR</code> <br />
先保存 <code>%AIR</code> 这个 Tasker 自带的飞行模式变量；</li>
<li>如果 <code>%AIR = off</code> 则运行外壳开启飞行模式；</li>
<li>如果 <code>%AIR = on</code> 则运行外壳开启 NFC；</li>
<li>如果 <code>%TMPAIR = on</code> 则运行外壳关闭飞行模式。</li>
</ol>
<h4 id="开启关闭飞行模式">开启关闭飞行模式</h4>
<p>开启和关闭飞行模式可以直接使用下面的两条命令：</p>
<pre class="brush: bash; title: ; notranslate">
settings put global airplane_mode_on 1; am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true
settings put global airplane_mode_on 0; am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false
</pre>
<h4 id="开启关闭-nfc">开启关闭 NFC</h4>
<p>开启和关闭 NFC 功能则相对复杂一些，需要区分 Android 系统版本：</p>
<ul>
<li>Android 4.4 以上：</li>
</ul>
<pre class="brush: bash; title: ; notranslate">
# Disable NFC
service call nfc 5
# Enable NFC
service call nfc 6
</pre>
<ul>
<li>Android 4.0.1 - Android 4.3.1：</li>
</ul>
<pre class="brush: bash; title: ; notranslate">
# Disable NFC
service call nfc 4
# Enable NFC
service call nfc 5
</pre>
<ul>
<li>Android 2.3.4 - Android 2.3.7：</li>
</ul>
<pre class="brush: bash; title: ; notranslate">
# Disable NFC
service call nfc 18
# Enable NFC
service call nfc 19
</pre>
<ul>
<li>Android 2.3.3：</li>
</ul>
<pre class="brush: bash; title: ; notranslate">
# Disable NFC
service call nfc 20
# Enable NFC
service call nfc 21
</pre>
<ul>
<li>Android 2.3.2：</li>
</ul>
<pre class="brush: bash; title: ; notranslate">
# Disable NFC
service call nfc 13
# Enable NFC
service call nfc 14
</pre>
<p>我在运行 Android 6.0 系统的 Zenfone2 手机上可以正常使用第一段的两条命令控制系统 NFC 功能。</p>
<h3 id="gps-开关-开启关闭百度地图">GPS 开关 + 开启关闭百度地图</h3>
<p>需求还是和之前的文章相同：</p>
<ol>
<li>刷 NFC 标签自动开启 GPS 和百度地图进行导航：</li>
<li>导航完成后再刷一次 NFC 标签自动关闭百度地图并关闭 GPS。</li>
</ol>
<p>为此我还是只建立一个 Tasker 任务，包含多个操作：</p>
<ol>
<li>Tasker 操作类别中选 <strong>变量</strong> -&gt; <strong>变量设置</strong>，<code>%TMPGPS</code> 发往 <code>%GPS</code> <br />
先保存 <code>%GPS</code> 这个 Tasker 自带的 GPS 设置变量；</li>
<li>如果 <code>%GPS = off</code> 则启动应用 -&gt; 百度地图；</li>
<li>如果 <code>%GPS = off</code> 则运行外壳开启 GPS；</li>
<li>如果 <code>%TMPGPS != on</code> 则停止运行任务（操作类别中选 <strong>任务</strong> -&gt; <strong>停止</strong>）忽略后续操作；</li>
<li>按钮 -&gt; 后退（操作类别中选 <strong>输入</strong> -&gt; <strong>按钮</strong>），此操作需要添加多个以模拟持续按返回键退出百度地图；</li>
<li>杀死应用 -&gt; 百度地图；</li>
<li>运行外壳关闭 GPS。</li>
</ol>
<p>通过 Shell 命令开启关闭 GPS 也稍微有点特殊，需要使用下面两条命令：</p>
<pre class="brush: bash; title: ; notranslate">
settings put secure location_providers_allowed +gps
settings put secure location_providers_allowed -gps
</pre>
<h2 id="后记">后记</h2>
<p>为了方便查询，我把一些可能经常用到的 Android Shell 控制命令也整理保存到我的 Wiki 知识库中了，读者可以点击 Wiki 链接 <a href="https://wiki.zohead.com/%E6%8A%80%E6%9C%AF/Android/Android%20Shell%E6%8E%A7%E5%88%B6%E6%89%8B%E6%9C%BA.md" target="_blank">Android Shell 控制手机</a> 查看。后续有其它 Shell 命令需要加进来或者修改时，我也会尽量及时更新该文档的，最后祝大家玩的开心。</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/tasker-shell/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>解决mintty在MSYS上无法启动的问题</title>
		<link>https://zohead.com/archives/mintty-msys/</link>
		<comments>https://zohead.com/archives/mintty-msys/#comments</comments>
		<pubDate>Thu, 23 Apr 2015 16:53:00 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[Windows]]></category>
		<category><![CDATA[cygwin]]></category>
		<category><![CDATA[DLL]]></category>
		<category><![CDATA[mintty]]></category>
		<category><![CDATA[MSYS]]></category>
		<category><![CDATA[rebase]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[基地址]]></category>

		<guid isPermaLink="false">http://zohead.com/?p=920</guid>
		<description><![CDATA[之前在 Windows 上模仿 Linux Shell 环境的 MSYS 工具集一直都是使用其自带的 rxvt 或者 Windows 命令行 Shell 终端工具，不过这两种终端的用户体验都是比较差的，有各种功能缺失的问题，好在最近发现有一款 mintty 软件可以用来替代 MSYS 和 Cygwin 上的默认终端工具，经过实际测试效果还是比 MSYS 和 Cygwin 自带的好很多的。 mintty 的项目网址： https://code.google.com/p/mintty/ 这两天使用 mintty 的时候却突然发现配合 MSYS 怎么也无法正常启动了，而且没有任何报错信息，最后通过  [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>之前在 Windows 上模仿 Linux Shell 环境的 MSYS 工具集一直都是使用其自带的 rxvt 或者 Windows 命令行 Shell 终端工具，不过这两种终端的用户体验都是比较差的，有各种功能缺失的问题，好在最近发现有一款 mintty 软件可以用来替代 MSYS 和 Cygwin 上的默认终端工具，经过实际测试效果还是比 MSYS 和 Cygwin 自带的好很多的。</p>
<p>mintty 的项目网址：</p>
<p><a href="https://code.google.com/p/mintty/" target="_blank">https://code.google.com/p/mintty/</a></p>
<p>这两天使用 mintty 的时候却突然发现配合 MSYS 怎么也无法正常启动了，而且没有任何报错信息，最后通过 MSYS 的 rxvt 终端运行才看到了报错提示：</p>
<pre class="brush: bash; title: ; notranslate">
[Administrator@msys ~]# mintty
m.AllocationBase 0x0, m.BaseAddress 0x68550000, m.RegionSize 0x4B0000, m.State 0x10000
C:\msys\bin\mintty.exe: *** Couldn't reserve space for cygwin's heap (0x68550000 &lt;0x13C0000&gt;) in child, Win32 error 0
</pre>
<p>在这个网址上看到了有人提出了使用 rebase 命令修改 MSYS DLL 文件首选基地址的解决方法：</p>
<p><a href="http://dreamcloud.artark.ca/msys-not-start/" target="_blank">http://dreamcloud.artark.ca/msys-not-start/</a></p>
<p>每个 DLL 文件都有一个首选的基地址，表示映射到使用的进程地址空间中的首选地址，一般默认为 0x10000000。实际情况下可执行程序一般会使用多个 DLL 文件，如果多个 DLL 文件都使用默认的首选基地址会造成系统自动做基地址重定位操作，这样可能导致进程地址空间中碎片的存在，并影响 DLL 的加载效率，因此有些 DLL 文件就直接自己指定了首选基地址。</p>
<p>如果需要查看某个 DLL 文件当前的基地址，可以使用 <strong>dumpbin.exe</strong> 命令行工具来查看，也可以使用 <strong>Dependency Walker</strong> 程序打开 mintty.exe 可执行文件，然后查看使用的 msys-1.0.dll 的基地址，例如我修改之前的效果如下图：</p>
<div style="width: 602px" class="wp-caption alignnone"><a href="http://res.cloudinary.com/digwht2y0/image/upload/v1737442856/msys-base.png" target="_blank"><img alt="查看DLL基地址" src="http://res.cloudinary.com/digwht2y0/image/upload/v1737442856/msys-base.png" width="592" height="403" /></a><p class="wp-caption-text">查看DLL基地址</p></div>
<p>从图中可以看出修改之前 msys-1.0.dll 文件的基地址（就是 Base 那一栏了）是 0x68000000。</p>
<p>按照上面链接提供的方法，首先需要退出 MSYS shell，并保证所有使用 MSYS DLL 的程序都停掉，先备份 msys-1.0.dll 文件，然后在 Cygwin 或者 cmd 里直接运行 rebase 命令修改 MSYS DLL 加载基地址为 0x76000000：</p>
<pre class="brush: bash; title: ; notranslate">
[Administrator@cygwin ~]# rebase -b 0x76000000 msys-1.0.dll
</pre>
<p>直接在 MSYS shell 里修改的话会由于 msys-1.0.dll 正在被使用而修改失败。修改成功之后重新运行 mintty.exe 程序，但还是有问题启动不了，报错信息相应也变了：</p>
<pre class="brush: bash; title: ; notranslate">
[Administrator@msys ~]# mintty
m.AllocationBase 0x763C0000, m.BaseAddress 0x76550000, m.RegionSize 0x23A000, m.State 0x1000
C:\msys\bin\mintty.exe: *** Couldn't reserve space for cygwin's heap (0x76550000 &lt;0x1610000&gt;) in child, Win32 error 0
</pre>
<p>看来这个修改过的基地址还是有问题的，估计还是和 mintty 程序有冲突的，我们再修改 DLL 基地址为 0x60100000 看看：</p>
<pre class="brush: bash; title: ; notranslate">
[Administrator@cygwin ~]# rebase -b 0x60100000 msys-1.0.dll
</pre>
<p>这下再运行 mintty 程序终于正常工作了，另外如果系统里没有 rebase 命令的话也可以使用 Visual Studio 2010 中自带的 <strong>editbin.exe</strong> 程序来修改 DLL 文件基地址的哦，玩的开心 ^_^。</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/mintty-msys/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<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>
		<item>
		<title>刚迷上screen就不得不马上移情tmux</title>
		<link>https://zohead.com/archives/terminal-screen-and-tmux/</link>
		<comments>https://zohead.com/archives/terminal-screen-and-tmux/#comments</comments>
		<pubDate>Mon, 14 May 2012 15:33:11 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[工具]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[screen]]></category>
		<category><![CDATA[Shell]]></category>
		<category><![CDATA[tmux]]></category>
		<category><![CDATA[终端]]></category>

		<guid isPermaLink="false">http://zohead.com/?p=157</guid>
		<description><![CDATA[本文同步自（如浏览不正常请点击跳转）：https://zohead.com/archives/terminal-screen-and-tmux 一个星期之前调试代码时用上 GNU screen，这个多终端模拟器，对我而言很大程度上摆脱了调试时必须开N个 SecureCRT 远程登录标签的郁闷，而且很多 Linux 发行版上都已经自带 screen 包，直接安装即可，也可以在这下载自己编译： http://www.gnu.org/software/screen/ screen 的快捷键操作非常简单（文本模式下的 Linux 必须要N多快捷键的说），安装之后，在一个终端里运行 screen 命令就 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>本文同步自（如浏览不正常请点击跳转）：<a href="https://zohead.com/archives/terminal-screen-and-tmux" target="_blank">https://zohead.com/archives/terminal-screen-and-tmux</a></p>
<p>一个星期之前调试代码时用上 GNU screen，这个多终端模拟器，对我而言很大程度上摆脱了调试时必须开N个 SecureCRT 远程登录标签的郁闷，而且很多 Linux 发行版上都已经自带 screen 包，直接安装即可，也可以在这下载自己编译：</p>
<p><a href="http://www.gnu.org/software/screen/" target="_blank">http://www.gnu.org/software/screen/</a></p>
<p>screen 的快捷键操作非常简单（文本模式下的 Linux 必须要N多快捷键的说），安装之后，在一个终端里运行 screen 命令就可以启动，可以在一个终端里再创建新的 shell，使用快捷键在不同的 shell 之间切换，使用 screen 的 detach shell 可实现更好的后台任务处理，用起来还是比较 happy，无奈 GNU screen 也有一些缺陷：</p>
<p><em>1、不支持在一个 shell window 里再拆分子窗口，也就是像 vim 的多窗口编辑效果；</em><br />
<em> 2、对 xterm 终端支持一般；</em><br />
<em> 3、不能自己根据启动 screen 时的窗口大小调节新 shell 的大小，这个小郁闷；</em><br />
<em> ......</em></p>
<p>今天看到一哥们分享的 tmux 终端复用工具，立马感觉我要不淡定的移情了，在此下载：</p>
<p><a href="http://sourceforge.net/projects/tmux/" target="_blank">http://sourceforge.net/projects/tmux/</a></p>
<p>tmux 对比 screen 的优点：单个 shell window 拆分很强大，移动切换 shell pane 很强大，完美支持 xterm 终端和集成原 shell 大小，BSD license，命名 shell window，OOO，受不了先上图：</p>
<p><a href="http://zohead.com/wp-content/uploads/tmux-multi-screen.jpg" target="_blank"><img class="alignnone" title="tmux终端" src="http://zohead.com/wp-content/uploads/tmux-multi-screen.jpg" alt="tmux终端" width="492" height="263" /></a></p>
<p>图中是我实际使用的一个环境，pane 0 查看 man 帮助，pane 1 修改代码，pane 2 命令操作，pane 3 监控系统。</p>
<p>tmux 的快捷键和 screen 的有点类似，只是初始快捷键改为了 Ctrl+B：</p>
<p>Ctrl-B-C ：创建新窗口；<br />
Ctrl-B-D ：detach窗口，和 screen 的类似；<br />
Ctrl-B-"  ：将当前窗口拆分为上下两行；<br />
Ctrl-B-%：将当前窗口拆分为左右两列；<br />
Ctrl-B-上下左右：切换 shell pane<br />
......</p>
<p>具体请看 man tmux，果断强烈推荐了，tmux现在除了不是在每个 Linux 发行版中默认就附带这点似乎没有什么相比 screen 的缺点了（不过我还是下到了编译好的 RHEL6 上的 RPM 包，哈哈）。</p>
<p>tmux得在以后使用时继续研究咯，screen暂时抛弃，玩的开心~~~ ^_^</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/terminal-screen-and-tmux/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
