退出当前 Bash Shell 并不保存历史的 5 种方法

某些时候我们希望在退出 Bash Shell 的时候不要保存执行命令的历史记录,那么可以用以下几种方法来实现:

先说两个不影响以前的历史记录的方法:

1. 修改 HISTFILE 变量

unset HISTFILE && exit

2. 直接 Kill 当前 Shell

kill -9 $$

下面三个方法会清除所有的记录:

3. 清除历史记录并退出

history -c && exit

4. 设置历史记录保存数量为 0 条并退出

HISTSIZE=0 && exit

5. 删除历史记录文件并修改 HISTFILE 变量

rm -f $HISTFILE && unset HISTFILE && exit

如果你想每次都自动执行这些命令,可以在将对应的指令添加到 ~/.bash_logout 文件中,或者使用 alisa 功能。

译自:http://www.if-not-true-then-false.com/2010/quit-bash-shell-without-saving-bash-history/

搭建需要身份认证的 Squid 代理

1. 安装 Squid

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install squid

或者

yum install squid

2. 配置 HTTP 代理
注意,在 Ubuntu 下配置文件的默认位置可能是 /etc/squid3/,下面均用 CentOS 的 /etc/squid/ 举例,请自行替换。
基础设置:
首先设置允许访问该代理的 IP 列表:

# /etc/squid/squid.conf
acl client src 12.34.56.78 #客户端1 IP 地址
acl client src 21.43.56.78 #客户端2 IP 地址
...
http_access allow client

注意这几行要加在配置文件原有的

http_access deny all

之前,不然不会生效。
然后重启 squid 服务,让配置生效。

service squid restart #CentOS
service squid3 restart #Ubuntu

注意!非常不建议使用 http_access allow all,你的代理一定会被别人扫到用来干坏事!

高级验证:
如果想使用用户名密码来做权限控制,则需要进行一些额外的配置:
首先,我们需要安装 htpasswd,这个工具集成在 apache httpd 的 tools 里面

apt-get install apache2-utils
yum install httpd-tools

安装完成之后执行 htpasswd,如果没有提示找不到命令,则说明安装成功。
接下来创建保存用户名密码的文件:

touch /etc/squid/squid_passwd
chown squid /etc/squid/squid_passwd

注意授权的时候要弄清楚 squid 运行时的用户名,一般是 squid 或者 proxy。
然后执行:

htpasswd /etc/squid/squid_passwd username
New password:
Re-type new password:
Adding password for user username

注意把 username 换成你想要的用户名。
如果想要继续添加用户,请多次执行这条命令。

接下来修改 /etc/squid/squid.conf 文件,在 http_access deny all 之前加上下面几句:

auth_param basic program /usr/lib/squid/ncsa_auth /etc/squid/squid_passwd
auth_param basic children 5
auth_param basic realm Squid proxy-caching web server
auth_param basic credentialsttl 2 hours
auth_param basic casesensitive off

acl ncsa_users proxy_auth REQUIRED
http_access allow ncsa_users
这里要注意,如果你的系统是 64 位的,那么 /usr/lib/squid/ncsa_auth 这个模块的地址应该是 /usr/lib64/squid/ncsa_auth。设置之前建议用这个命令来检查一下:
dpkg -L squid | grep ncsa_auth
rpm -ql squid | grep ncsa_auth

下面说说这几个选项的含义:
auth_param basic program /usr/lib/squid/ncsa_auth /etc/squid/squid_passwd : 指定密码文件和用来验证密码的程序
auth_param basic children 5 : 鉴权进程的数量
auth_param basic realm Squid proxy-caching web server : 用户输入用户名密码时看到的提示信息
auth_param basic credentialsttl 2 hours : 用户名和密码的缓存时间,也就是说同一个用户名多久会调用 ncsa_auth 一次。
auth_param basic casesensitive off : 用户名是否需要匹配大小写
acl ncsa_users proxy_auth REQUIRED : 所有成功鉴权的用户都归于 ncsa_users 组
http_access allow ncsa_users : 允许 ncsa_users 组的用户使用 Proxy

配置完成后重启 Squid 就可以啦!

3. 匿名
默认情况下,Squid 会添加很多和客户信息相关的 HTTP 头,如 X-Forwarded-For 这类。如果想要做到高度匿名,需要将这些头去掉。在 squid.conf 里面添加如下的配置:

forwarded_for off
request_header_access Allow allow all
request_header_access Authorization allow all
request_header_access WWW-Authenticate allow all
request_header_access Proxy-Authorization allow all
request_header_access Proxy-Authenticate allow all
request_header_access Cache-Control allow all
request_header_access Content-Encoding allow all
request_header_access Content-Length allow all
request_header_access Content-Type allow all
request_header_access Date allow all
request_header_access Expires allow all
request_header_access Host allow all
request_header_access If-Modified-Since allow all
request_header_access Last-Modified allow all
request_header_access Location allow all
request_header_access Pragma allow all
request_header_access Accept allow all
request_header_access Accept-Charset allow all
request_header_access Accept-Encoding allow all
request_header_access Accept-Language allow all
request_header_access Content-Language allow all
request_header_access Mime-Version allow all
request_header_access Retry-After allow all
request_header_access Title allow all
request_header_access Connection allow all
request_header_access Proxy-Connection allow all
request_header_access User-Agent allow all
request_header_access Cookie allow all
request_header_access All deny all

然后重启就可以啦!

默认情况下,Squid 会把主机相关的信息发送出去,并显示在错误页面。加上下面两句去掉这些信息:

# add this to /etc/squid/squid.conf
visible_hostname mybogusproxyhostname.local
# and while we are at it stop squid blabbing about it's version aswell
httpd_suppress_version_string on

最后说一个小坑,apache httpd 2.2 版本和 2.4 版本的 htpasswd 生成的密码文件格式是不一样的。只有 2.2 版本的能用。
如果按照教程设置成功以后发现用户名密码死活不对,文件权限也没有问题的话,那就要看一下是不是 htpasswd 的问题了。
直接输入 /usr/lib/squid/ncsa_auth /etc/squid/squid_passwd 然后输入 username passwd 可以手动运行一下 ncsa_auth 程序,看看是否是密码文件的问题。
如果提示 OK 那么说明没有问题,提示 ERR Wrong password 则说明要么是密码输错了,要么是密码文件的格式有问题。

PS:放出一个最简单的 PAC 文件,用来做代理的按需访问:

function FindProxyForURL(url, host) {
   if(ProxyDomain(url, host)) {
       return "PROXY 1.2.3.4:8080";
   }
   else {
       return "DIRECT";
   }
}

function ProxyDomain(url, host) {
    if(
        shExpMatch(host, "*.maoxian.de") ||
        shExpMatch(host, "*.baidu.com")
    ) {
        return true
    }
    return false;
}

PS:

编译安装的时候要注意一点,从 3.2 开始,编译使用的参数有了一点小变化,原先的:

--enable-auth="basic" --enable-baisc-auth-#helpers="NCSA"

变成了

--enable-auth  \
--enable-auth-basic=NCSA \

同时配置文件里的 /usr/lib/squid/ncsa_auth 模块可能会变成 /usr/bin/basic_ncsa_auth ,需要注意。

https://www.linode.com/docs/networking/squid/squid-http-proxy-ubuntu-12-04

常用 openssl 命令

The Most Common OpenSSL Commands

One of the most versatile SSL tools is OpenSSL which is an open source implementation of the SSL protocol. There are versions of OpenSSL for nearly every platform, including Windows, Linux, and Mac OS X. OpenSSL is commonly used to create the CSR and private key for many different platforms, including Apache. However, it also has hundreds of different functions that allow you to view the details of a CSR or certificate, compare an MD5 hash of the certificate and private key (to make sure they match), verify that a certificate is installed properly on any website, and convert the certificate to a different format. A compiled version of OpenSSL for Windows can be found here.

If you don’t want to bother with OpenSSL, you can do many of the same things with our SSL Certificate Tools. Below, we have listed the most common OpenSSL commands and their usage:

General OpenSSL Commands

These commands allow you to generate CSRs, Certificates, Private Keys and do other miscellaneous tasks.

  • Generate a new private key and Certificate Signing Request
    openssl req -out CSR.csr -new -newkey rsa:2048 -nodes -keyout privateKey.key
  • Generate a self-signed certificate (see How to Create and Install an Apache Self Signed Certificate for more info)
    openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout privateKey.key -out certificate.crt
  • Generate a certificate signing request (CSR) for an existing private key
    openssl req -out CSR.csr -key privateKey.key -new
  • Generate a certificate signing request based on an existing certificate
    openssl x509 -x509toreq -in certificate.crt -out CSR.csr -signkey privateKey.key
  • Remove a passphrase from a private key
    openssl rsa -in privateKey.pem -out newPrivateKey.pem

Checking Using OpenSSL

If you need to check the information within a Certificate, CSR or Private Key, use these commands. You can also check CSRs and check certificates using our online tools.

  • Check a Certificate Signing Request (CSR)
    openssl req -text -noout -verify -in CSR.csr
  • Check a private key
    openssl rsa -in privateKey.key -check
  • Check a certificate
    openssl x509 -in certificate.crt -text -noout
  • Check a PKCS#12 file (.pfx or .p12)
    openssl pkcs12 -info -in keyStore.p12

Debugging Using OpenSSL

If you are receiving an error that the private doesn’t match the certificate or that a certificate that you installed to a site is not trusted, try one of these commands. If you are trying to verify that an SSL certificate is installed correctly, be sure to check out the SSL Checker.

  • Check an MD5 hash of the public key to ensure that it matches with what is in a CSR or private key
    openssl x509 -noout -modulus -in certificate.crt | openssl md5
    openssl rsa -noout -modulus -in privateKey.key | openssl md5
    openssl req -noout -modulus -in CSR.csr | openssl md5
  • Check an SSL connection. All the certificates (including Intermediates) should be displayed
    openssl s_client -connect www.paypal.com:443

Converting Using OpenSSL

These commands allow you to convert certificates and keys to different formats to make them compatible with specific types of servers or software. For example, you can convert a normal PEM file that would work with Apache to a PFX (PKCS#12) file and use it with Tomcat or IIS. Use our SSL Converter to convert certificates without messing with OpenSSL.

  • Convert a DER file (.crt .cer .der) to PEM
    openssl x509 -inform der -in certificate.cer -out certificate.pem
  • Convert a PEM file to DER
    openssl x509 -outform der -in certificate.pem -out certificate.der
  • Convert a PKCS#12 file (.pfx .p12) containing a private key and certificates to PEM
    openssl pkcs12 -in keyStore.pfx -out keyStore.pem -nodes

    You can add -nocerts to only output the private key or add -nokeys to only output the certificates.

  • Convert a PEM certificate file and a private key to PKCS#12 (.pfx .p12)
    openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt -certfile CACert.crt

Originally posted on Sun Jan 13, 2008

https://www.sslshopper.com/article-most-common-openssl-commands.html

dd 常用命令汇总

生成指定大小的文件

dd if=/dev/urandom of=sample.txt bs=1G count=1
dd if=/dev/urandom of=sample.txt bs=64M count=16

dd if=/dev/random of=sample.txt bs=1G count=1
dd if=/dev/random of=sample.txt bs=64M count=16

测试磁盘的读写速度

一般常用的能查到的测试磁盘读写速度的命令是下面几个:

dd bs=1M count=256 if=/dev/zero of=test
dd bs=1M count=256 if=/dev/zero of=test; sync
dd bs=1M count=256 if=/dev/zero of=test conv=fdatasync
dd bs=1M count=256 if=/dev/zero of=test oflag=dsync

但是实际上,这几个的效果并不完全相同:

  1. dd bs=1M count=256 if=/dev/zero of=test
    The default behaviour of dd is to not “sync” (i.e. not ask the OS to completely write the data to disk before dd exiting). The above command will just commit your 256 MB of data into a RAM buffer (write cache) – this will be really fast and it will show you the hugely inflated benchmark result right away. However, the server in the background is still busy, continuing to write out data from the RAM cache to disk.
    dd 的默认行为是不做任何“同步”操作(也就是说,不要求操作系统在 dd 终止前完整的将数据写入磁盘。)上面那个命令只会给你分配 256M 的 RAM 缓存(写缓存)- 这个操作是非常快的,会告诉你非常夸张的测试觉果。但是实际上,服务器本身还在后台繁忙的进行写入操作,来将你刚刚写入 RAM 缓存的数据同步到磁盘。

    # dd bs=1M count=256 if=/dev/zero of=test
    256+0 records in
    256+0 records out
    268435456 bytes (268 MB) copied, 0.217855 s, 1.2 GB/s
  2. dd bs=1M count=256 if=/dev/zero of=test; sync
    Absolutely identical to the previous case, as anyone who understands how *nix shell works should surely know that adding a ; sync does not affect the operation of previous command in any way, because it is executed independently, after the first command completes. So your (inflated) MB/sec value is already printed on screen while that sync is only preparing to be executed.
    跟上一个命令完全相同。任何知道 *nix shell 如何运作的人都一定知道只是加一个 ; sync 并不会影响签名一条命令,因为这两条命令是完全分开执行的,添加的 sync 是在 dd 执行结束之后才会执行的。所以当你看到夸张的 MB/s 的值的时候,sync 命令才刚刚开始准备执行。

    # dd bs=1M count=256 if=/dev/zero of=test; sync
    256+0 records in
    256+0 records out
    268435456 bytes (268 MB) copied, 0.225096 s, 1.2 GB/s
    (Waiting for sync)
    #
  3. dd bs=1M count=256 if=/dev/zero of=test conv=fdatasync
    This tells dd to require a complete “sync” once, right before it exits. So it commits the whole 256 MB of data, then tells the operating system: “OK, now ensure this is completely on disk”, only then measures the total time it took to do all that and calculates the benchmark result.
    这条指令告诉 dd 在退出之前必须要等待“同步”结束。所以该命令先是创建了 256M 的数据,然后告诉系统:“现在确认这些数据已经写到了磁盘上”,然后才开始停止计时并计算测试的结果。

    # dd bs=1M count=256 if=/dev/zero of=test conv=fdatasync
    256+0 records in
    256+0 records out
    268435456 bytes (268 MB) copied, 1.54606 s, 174 MB/s
  4. dd bs=1M count=256 if=/dev/zero of=test oflag=dsync
    Here dd will ask for completely synchronous output to disk, i.e. ensure that its write requests don’t even return until the submitted data is on disk. In the above example, this will mean sync’ing once per megabyte, or 256 times in total. It will be the slowest mode, as the write cache is basically unused at all in this case.
    这条命令 dd 会要求完全同步写入磁盘,也就是说,任何一个写入请求在数据完全保存到磁盘之前都不会返回。在上面这条命令里,这代表 dd 将会每 1MB 同步一次,或者说一共要同步256次。所以这是最慢模式,因为这种情况下基本上完全没有使用缓存。

    # dd bs=1M count=256 if=/dev/zero of=test oflag=dsync
    256+0 records in
    256+0 records out
    268435456 bytes (268 MB) copied, 2.40251 s, 112 MB/s

    当然有时候连续执行第三条和第四条命令,第四条并不比第三条慢。这可能是由于其他应用的 IO 占用导致的。

所以,一般情况下推荐使用第三条命令来进行测试,尽可能快的得到尽可能准确的结果。

原文地址:https://romanrm.net/dd-benchmark

使用 Nginx 反代 Apache 安装 WordPress

最近由于原先博客主机极度不稳定,所以准备了很久,准备进行主机迁移。由于迁移前的环境和迁移后还是有较大的区别,整体架构也不太一样,所以在这里说说迁移过程中遇到的问题。

环境对比

原主机 新主机
操作系统 CentOS 6 CentOS 7
Web 服务器 Apache 2.2 Openresty 1.9.7 + Apache 2.4
PHP 版本 5.5 5.6
其他 SELinux

SELinux

很多人为了省事,在拿到主机的第一时间就直接禁用了 SELinux。不过在学习了一段时间之后,我发现其实 SELinux 是一个很好的保护机器的手段。

这里简单列举几个需要注意的 SELinux 的配置:

 

httpd_can_network_connect_db boolean 类型,控制 Apache 是否可以连接 DB
http_port_t port 类型,控制 Apache 可以监听的端口
mysqld_port_t port 类型,控制 mysql 可以监听的端口和 Apache 可以连接的 DB 端口

由于我是将 Apache 作为只解析后端 PHP 请求使用,所以需要修改 http_port_t 加入我需要的端口。添加方法类似于:

semanage port -a -t http_port_t  -p tcp 8090

另外由于我没有在本机安装 Mysql 而是使用的远程 Mysql 实例,并且开放的端口并不是标准的 3306,所以需要将端口号添加到 mysqld_port_t 中。

Apache

这玩意是主要的坑所在。下面来一一列举。

配置格式变更

Apache 2.2 和 2.4 的配置文件区别还是比较大的,加了很多新的参数,同时修改了很多配置的方法。最明显的是:

Options -Indexes

Allow from all
Deny from all

这三条配置已经完全被改掉了。如果在配置中出现第一种,会直接起不来。后面的 Allow Deny 的写法虽然不会有问题,但是已经不是官方推荐的了,建议改掉。

配置无效

在配置 Apache 2.4 的 Log Format 的时候,我发现了一个很蛋疼的问题,就是 CentOS yum 安装的版本(2.4.6)有些配置是使用不了的。如:

http://httpd.apache.org/docs/2.4/mod/mod_log_config.html

这个文档中的:

%{UNIT}T	The time taken to serve the request, in a time unit given by UNIT. Valid units are ms for milliseconds, us for microseconds, and s for seconds. Using s gives the same result as %T without any format; using us gives the same result as %D. Combining %T with a unit is available in 2.4.13 and later.

很多参数都有类似的标注(available in 2.4.13 and later),告诉你在旧版本中不能使用。如果不仔细看的话很容易忽略。所以配置之前一定要仔细阅读。

HTTPS

WordPress

由于我的博客是全站 HTTPS 的,因此在 WordPress 上我是有做一些强制 HTTPS 的措施。但是!由于 WordPress 默认的检测 HTTPS 的方法是这样的:

/**
 * Determine if SSL is used.
 *
 * @since 2.6.0
 *
 * @return bool True if SSL, false if not used.
 */
function is_ssl() {
        if ( isset($_SERVER['HTTPS']) ) {
                if ( 'on' == strtolower($_SERVER['HTTPS']) )
                        return true;
                if ( '1' == $_SERVER['HTTPS'] )
                        return true;
        } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
                return true;
        }
        return false;
}

而我的 HTTPS 是在 Nginx 层做的,所以导致这两个条件均不满足,因此会遇到重定向循环(Redirect Loop)的问题。解决方法有两种:

修改 wp-config.php 文件:

if ( isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && ( 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) {
    $_SERVER['HTTPS'] = 'on';
}

这里的修改需要配合修改 Nginx 的 Proxy 设置,增加下面这行:

proxy_set_header X-Request-Protocol $scheme; #http or https

修改 wp-includes/functions.php 文件(4025行左右):

找到上面说的那段代码,将其替换为:

/**
 * Determine if SSL is used.
 *
 * @since 2.6.0
 *
 * @return bool True if SSL, false if not used.
 */
function is_ssl() {
        if ( isset($_SERVER['HTTPS']) ) {
                if ( 'on' == strtolower($_SERVER['HTTPS']) )
                        return true;
                if ( '1' == $_SERVER['HTTPS'] )
                        return true;
        } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
                return true;
        } elseif ( isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && ( 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) {
                return true;
        }
        return false;
}

同时这个修改方法也要配合修改 Nginx 的 Proxy 设置。

注意,虽然可以不做判断直接无脑 $_SERVER[‘HTTPS’] = ‘on’; 或者在那个 is_ssl() 方法中无脑返回 true,但是不建议这样修改。因为这样可能会导致安全上面的问题。

Apache .htaccess

由于我在某些目录中通过 .htaccess 的方式强制重定向了非 HTTPS 请求,因此在将 SSL 交给 Nginx 之后相关的跳转判断也要修改。原先的跳转逻辑是:

RewriteEngine on
RewriteCond   %{HTTPS} !=on
RewriteRule   ^(.*)  https://%{SERVER_NAME}/$1 [L,R]

由于 %{HTTPS} 这个变量判断的是 Apache 传进来的内部参数,我们无法控制,所以需要将这段修改为:

RewriteEngine on
RewriteCond %{HTTP:X-Request-Protocol} ^http$
RewriteRule   ^(.*)  https://%{SERVER_NAME}/$1 [L,R]

这里判断的就是 Nginx 传进来的 X-Request-Protocol 头了。不过这种写法并不能在单独使用 Apache 作为 Web 服务器的时候使用,需要注意。

客户端证书

目前只针对某目录或文件的客户端证书配置还没有测试完成,将在后面更新。

Compiling Nginx with HTTP/2 and ALPN

To have HTTP/2 fully supported in Nginx, you will need OpenSSL 1.0.2+ to have APLN enabled (What is APLN)

Unfortunately, nowadays most linux distributions are shipping with older version of OpenSSL. For example Ubuntu 14.04 is using openssl 1.0.1f

I can also use 3rd party repositories but I couldn’t find out something I think it is trusted

So it leaves me with only one option: compiling from source

Good thing is, it is pretty easy to compile nginx with a custom OpenSSL. You don’t even have to compile the OpenSSL and install into the system (which could break your system dependences)

All you have to do are:

  1. Download the latest stable OpenSSL from https://www.openssl.org/source/ and extract the tar
  2. Download the latest stable nginx from http://nginx.org/en/download.html and extract the tar
  3. Go into nginx source folder and
    ./configure --with-openssl=/path/to/openssl-1.0.2f --with-http_ssl_module --with-http_v2_module
    make && make install
    • Note: –with-openssl points to the openssl source folder instead of the installation folder
  4. Enable HTTP/2 in nginx configure file

That’s it

And here is how you can verify if your website is now supporting HTTP/2 and ALPN

echo |  /usr/local/ssl/bin/openssl s_client -alpn h2 -connect c11e.wodemo.com:443 | grep ALPN

Which will report

  • “ALPN protocol: h2”
  • or “No ALPN negotiated”

什么是 ALPN(应用层协议协商) What is ALPN (Application-Layer Protocol Negotiation)

在没有启用 ALPN 的时候,加载一个 HTTP/2 页面的步骤是:

Without ALPN, the steps to load a HTTP/2 page would be like:

  1. TLS 握手 (TLS handshake)
  2. 浏览器/客户端 发送带有 “Upgrade: h2c” 头的 HTTP/1.1 请求 (Browser/Client speaks HTTP/1.1 to server with “Upgrade: h2c” Header)
  3. 服务器回复 101 Switching 并将链接升级至 HTTP2 (Server responds with 101 Switching to upgrade to HTTP2)
  4. 现在服务器和客户端采用 HTTP2 协议交流 (Now they talks via HTTP2)

在启用了 ALPN 的情况下:

With ALPN, the steps would be:

  1. TLS握手,并且在握手过程中,客户端告诉服务器一个客户端支持的协议列表,然后服务器回复客户端支持 HTTP2 协议 (TLS handshake and in the handshake client tells the server the list of protocol it supports and server respond in handshake saying that it supports HTTP2 as well)
  2. 现在服务器和客户端采用 HTTP2 协议交流 (Now they talks via HTTP2)

可以看出,使用 ALPN 之后,客户端和服务器的交互少了一轮握手(不需要 Upgrade 和 101 Switching)

As you can see there is one less round trip with ALPN (No step of Upgrade and 101 Switching)

RFC: http://tools.ietf.org/html/rfc7301

修复 Mac OS X 新版 Terminal 在 SSH 时候出现的 LANGUAGE WARNING

自从升级了新版的 Mac OS X 之后,使用 Terminal SSH 到别的机器上总是能看到这样的警告:

-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory

在执行 perl 脚本的时候还能看到这样的警告:

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
    LANGUAGE = (unset),
    LC_ALL = (unset),
    LANG = "en_US.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").

找了很多方法,包括改服务端 sshd config 什么的,都觉得不好。因为这应该不是服务端的问题,不应该在服务端解决。于是仔细搜索之后发现这个回答完美解决了这个问题:

http://stackoverflow.com/questions/2499794/how-can-i-fix-a-locale-warning-from-perl/7413863#7413863

Here is how to solve it on Mac OS Lion (10.7):

Add the following lines to your bashrc or bash_profile on the host machine:

# Setting for the new UTF-8 terminal support in Lion
export LC_CTYPE=en_US.UTF-8
export LC_ALL=en_US.UTF-8

If you are using zsh, edit zshrc:

# Setting for the new UTF-8 terminal support in Lion
LC_CTYPE=en_US.UTF-8
LC_ALL=en_US.UTF-8

Linux find 与 rm 联动删除符合条件的文件

xargs 方法

find . -name 'file*' -size 0 -print0 | xargs -0 rm

首先 find 找到符合条件的文件并输出文件名,然后管道传递给 xargs,然后由 xargs 拼接出结果。

需要注意的是 -print0 的意思是用一个 \0 作为分隔符,是用来配合 xargs 的 -0 (使用\0作为分隔符)使用的。

GUN find 法

find -name 'file*' -size 0 -delete

GUN find 直接支持了 -delete 参数,甚至还有 -ls 参数,可以自动在找到符合要求的文件之后进行删除或列出详细信息的操作。目前大部分 Linux 发行版用的都是 GUN find,所以该方法比较通用。但是如果你的 Linux 发行版中安装的 find 不支持这两个参数,那么就不能使用这个方法了。

find -exec 法

find . -name file* -exec rm {} \;
find . -name file* -exec rm {} \+

第一行的写法是将找到的文件名拼接到 {} 中,然后执行命令。第二行类似,不同的是把所有文件名拼接成一条命令。也就是说,用方法一,如果 find 的结果是

1
2
3

那么最终就会看到:

rm 1
rm 2
rm 3

这样三个进程。但是使用方法二,则会看到:

rm 1 2 3

只有一个进程,效率更高。

但是需要注意的是,命令参数是有长度限制的,如果文件过多,可能会出现:

cannot execute [Argument list too long]

这是因为参数过多,超过了系统限制。这时候用方法一就能避免这个问题。

Update: 这里说一个 find 命令的小坑。如果想用 find 找到指定大小的文件并删除的话,应该这么写条件:

find ./ -size 100k
find ./ -size 100M
find ./ -size 100G

注意此处是精确匹配。不过可以在数值之前加 +/- 来进行大于或小于的匹配:

find ./ -size +100k #找所有大于 100K 的文件
find ./ -size -100M #找所有小于 100M 的文件
find ./ -size +100G

但是!我上面说的最低的单位都是 K,如果是 Byte 作为单位要怎么办呢?下面两种哪种对?还是都可以?

find ./ -size 100b
find ./ -size 100

实际上,这两种都是错的。来看看实际操作:

➜  test ll
total 8
drwxr-xr-x    3 John  staff   102B May 24 09:53 ./
drwxr-xr-x  118 John  staff   3.9K May 24 09:53 ../
-rw-r--r--    1 John  staff    14B May 24 09:53 test
➜  test find ./ -size 14
➜  test find ./ -size 14b
find: -size: 14b: illegal trailing character
➜  test find ./ -size 14c
.//test
➜  test

可以看出,当单位是 Byte 的时候,正确的写法是用 c 作为单位后缀。具体可见 find 的 man page

       -size n[ckMGTP]
             True if the file's size, rounded up, in 512-byte blocks is n.  If n is followed by a c, then the primary is true if the file's size is n bytes (characters).  Similarly if n is followed by a scale indicator then the file's size is compared to n scaled as:

             k       kilobytes (1024 bytes)
             M       megabytes (1024 kilobytes)
             G       gigabytes (1024 megabytes)
             T       terabytes (1024 gigabytes)
             P       petabytes (1024 terabytes)
       -size n[cwbkMG]
              File uses n units of space.  The following suffixes can be used:

              `b'    for 512-byte blocks (this is the default if no suffix is used)

              `c'    for bytes

              `w'    for two-byte words

              `k'    for Kilobytes (units of 1024 bytes)

              `M'    for Megabytes (units of 1048576 bytes)

              `G'    for Gigabytes (units of 1073741824 bytes)

              The  size  does  not  count indirect blocks, but it does count blocks in sparse files that are not actually allocated.  Bear in mind that the `%k' and `%b' format specifiers of -printf handle sparse files
              differently.  The `b' suffix always denotes 512-byte blocks and never 1 Kilobyte blocks, which is different to the behaviour of -ls.

关于这个默认为什么是 512-byte block,我查了一下相关资料,应该是因为早起在 IBM AIX 系统上 du 的默认单位就是 512-byte block,这是一个 POSIX 标准。这点从 dd 等命令的默认大小也能看出来:

➜  test dd if=/dev/random of=test count=1
1+0 records in
1+0 records out
512 bytes transferred in 0.000074 secs (6905092 bytes/sec)
➜  test ll
total 8
drwxr-xr-x    3 John  staff   102B May 24 09:53 ./
drwxr-xr-x  118 John  staff   3.9K May 24 09:53 ../
-rw-r--r--    1 John  staff   512B May 24 10:02 test

而且在造出了一个刚好 512B 的文件之后,我将其复制一份加了一个字符,达到 515B,然后再来试试 find 命令:

➜  test ll
total 16
drwxr-xr-x    4 John  staff   136B May 24 10:02 ./
drwxr-xr-x  118 John  staff   3.9K May 24 09:53 ../
-rw-r--r--    1 John  staff   512B May 24 10:02 test
-rw-r--r--    1 John  staff   515B May 24 10:02 test2
➜  test find ./ -size 1
./
.//test
➜  test find ./ -size 2
.//test2
➜  test

可以看到,正如文档中描述了,find 会直接向上取整来进行比较,然后返回结果。