在PHP中,执行一段shell命令非常简单,直接调用语言函数exec()
,system()
等即可完成,而且返回值也是显而易见的。但Java不是,做不到这么简单。
比如在PHP中简单执行exec("la -al")
的结果:
// @see http://php.net/manual/zh/function.exec.php
exec('ls -l', $output);
print_r($output);
输出:
zhgxun-pro:~ zhgxun$ php test.php
Array
(
[0] => total 8
[1] => drwx------+ 13 zhgxun staff 442 Jan 21 19:57 Desktop
[2] => drwx------+ 10 zhgxun staff 340 Jan 4 22:12 Documents
[3] => drwx------+ 9 zhgxun staff 306 Jan 20 11:45 Downloads
[4] => drwx------@ 56 zhgxun staff 1904 Dec 16 14:40 Library
[5] => drwx------+ 3 zhgxun staff 102 Aug 24 2015 Movies
[6] => drwx------+ 6 zhgxun staff 204 Dec 21 23:00 Music
[7] => drwx------+ 8 zhgxun staff 272 Mar 27 2017 Pictures
[8] => drwxr-xr-x+ 9 zhgxun staff 306 Dec 25 09:23 Public
[9] => drwxr-xr-x 2 zhgxun staff 68 Aug 14 14:37 Snapshots
[10] => drwxr-xr-x 4 zhgxun staff 136 Mar 28 2017 Soft
[11] => drwxr-xr-x 6 zhgxun staff 204 May 10 2017 go
[12] => -rw-r--r-- 1 zhgxun staff 56 Jan 21 19:56 test.php
)
zhgxun-pro:~ zhgxun$ ls -l
total 8
drwx------+ 13 zhgxun staff 442 Jan 21 19:57 Desktop
drwx------+ 10 zhgxun staff 340 Jan 4 22:12 Documents
drwx------+ 9 zhgxun staff 306 Jan 20 11:45 Downloads
drwx------@ 56 zhgxun staff 1904 Dec 16 14:40 Library
drwx------+ 3 zhgxun staff 102 Aug 24 2015 Movies
drwx------+ 6 zhgxun staff 204 Dec 21 23:00 Music
drwx------+ 8 zhgxun staff 272 Mar 27 2017 Pictures
drwxr-xr-x+ 9 zhgxun staff 306 Dec 25 09:23 Public
drwxr-xr-x 2 zhgxun staff 68 Aug 14 14:37 Snapshots
drwxr-xr-x 4 zhgxun staff 136 Mar 28 2017 Soft
drwxr-xr-x 6 zhgxun staff 204 May 10 2017 go
-rw-r--r-- 1 zhgxun staff 56 Jan 21 19:56 test.php
zhgxun-pro:~ zhgxun$
然而使用Java,就没这么直接了。
package flight;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @see https://docs.oracle.com/javase/8/docs/api/index.html
*/
public class App {
public static void main(String[] args) {
Process process;
try {
process = Runtime.getRuntime().exec("ls -l");
process.waitFor();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
} catch (InterruptedException | IOException e) {
e.printStackTrace();
}
}
}
输出:
total 24
-rw-r--r-- 1 zhgxun staff 2651 Jan 18 22:53 balance.iml
drwxr-xr-x 3 zhgxun staff 102 Jan 21 18:06 data
-rw-r--r-- 1 zhgxun staff 1706 Jan 19 00:14 dependency-reduced-pom.xml
-rw-r--r-- 1 zhgxun staff 3613 Jan 18 22:55 pom.xml
drwxr-xr-x 5 zhgxun staff 170 Jan 20 14:13 src
drwxr-xr-x 11 zhgxun staff 374 Jan 19 00:14 target
Process finished with exit code 0
下面是一个综合使用Java的例子:
package flight;
import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
/**
* 周对账
*
* @author zhangguangxun
*/
public class Week {
// 基本目录
private static String BASEDIR = "";
// 周对账文件, 分GBK, UTF-8两种文件, GBK文件为提供给财务用, UTF-8为例行文件, 自行使用
private static String WEEKPATH = "";
private static String WEEKPATH_UTF8 = "";
private static String WEEKPATH_GBK = "";
/**
* 周对账
*
* @param from 对账开始时间
* @param to 对账截止时间
*/
public static void handler(String from, String to) {
// 1. 创建文件夹和文件
create(to);
// 2. 下载周对账文件
fetch(from, to);
// 3. 对账
// ...
}
/**
* 按年月为单位创建文件夹和周对账文件
*
* @param to 截止日期
*/
private static void create(String to) {
LocalDate localDate = LocalDate.parse(to);
int year = localDate.getYear();
int month = localDate.getMonthValue();
int day = localDate.getDayOfMonth();
BASEDIR = String.format("data/balance/%d/%d", year, month);
File file = new File(BASEDIR);
if (!file.exists()) {
if (!file.mkdirs()) {
System.out.println("Error create directory: " + BASEDIR);
System.exit(0);
}
}
WEEKPATH = String.format("%s/week_%d_%d.csv", BASEDIR, month, day);
WEEKPATH_UTF8 = String.format("%s/week_utf8_%d_%d.csv", BASEDIR, month, day);
WEEKPATH_GBK = String.format("%s/week_gbk_%d_%d.csv", BASEDIR, month, day);
}
/**
* 下载每天对账文件, 并将下载的文件合并为一个文件用于周对账
*
* @param from 开始时间
* @param to 截止时间
*/
private static void fetch(String from, String to) {
// 解析字符串格式的时间样式, 2018-01-21
LocalDate localDate = LocalDate.parse(from);
// 提供的时间是否为周的开始和结束
int firstDay = localDate.getDayOfWeek().getValue();
if (firstDay != 1) {
System.out.println("Error first day: " + firstDay);
System.exit(0);
}
int lastDay = LocalDate.parse(to).getDayOfWeek().getValue();
if (lastDay != 7) {
System.out.println("Error last day: " + lastDay);
}
Process process;
// 遍历一周的日期, 从钱包下载天对账数据, 并拼接写入到一个文件中
for (int i = firstDay; i <= lastDay; i++) {
int year = localDate.getYear();
int month = localDate.getMonthValue();
int day = localDate.getDayOfMonth();
// 下载每一天对账数据
String path = String.format("***/data/finance/product/052/2017/%d/052_%d-%d-%d.csv", month, year, month, day);
String local = String.format(BASEDIR + "/052_%d-%d-%d.csv", year, month, day);
String command = String.format("wget -O %s %s", local, path);
// 错误或下载异常时直接退出, 否则数据不完整
try {
process = Runtime.getRuntime().exec(command);
process.waitFor();
process = Runtime.getRuntime().exec(String.format("cat %s | sed '1,4d' >> %s", local, WEEKPATH));
process.waitFor();
// 删除天对账文件
File file = new File(local);
if (!file.delete()) {
System.out.println("Error delete file: " + local);
}
} catch (InterruptedException | IOException e) {
e.printStackTrace();
System.out.println("Error Down file: " + path);
System.exit(0);
}
// 加1天
localDate = localDate.plusDays(1);
}
}
}
当然,如果没有特别的性能考虑,还是推荐使用动态语言,比如PHP,Python。虽然可能这些语言不被人推荐,但是我们的确要看到这些语言实现的方式都非常简单,而且易于工作交界和后续维护。不过也要看编写代码人的水平和态度了,一份写的不完整或者杂乱无章的代码,其实是没意义的。
我在工作中就看到过很多公司的高级程序员编写的代码,不得不说维护他们的代码,是无比的糟糕和气愤,一方面也看出确实这个行业里的编写者,不管是所谓的高级工程师,还是管理者,写的代码很多还很差强人意的。这倒不是说写的东西要多难,让人佩服不已。其实不是的,写的东西,在满足需求的情况下,自然是越简单越好,而不是越容易应付越好。少给后续的维护者添加麻烦的代码,肯定不容易写。即使是很简单的功能,在一些人的手里,写出来的代码看了的确让人心寒,瞬间分分钟想离职避开这种没有责任心的是非之地。