Winse Blog

走走停停都是风景, 熙熙攘攘都向最好, 忙忙碌碌都为明朝, 何畏之.

Git实现多地多版本协作

具体情况:

  • 网络的版本库 github.com/winse/winse.github.com
  • 笔记本 /d/winsegit/winse.github.com/
  • U盘 /?/works/winse.github.com (盘符会变化)

想实现:以笔记本电脑上的更新为主,辅之U盘上的修改(上班时可能进行更新)。

使用SVN基本没法实现这种功能的。原来也没有深入的学习git,看了《Git权威指南》后豁然开朗!

  • Git允许一个版本库和任意多个的版本库进行交互 (第十九章 远程版本库)
  • Git本地库即可以作为客户端,也可以作为其他库的服务端!

实际操作

  • 把笔记本的winse.github.com程序拷贝到U盘中
  • 为U盘的版本库添加远程版本库notebook
  • U盘版本库建立新分支
  • U盘修改提交并push到远程版本库notebook
  • 笔记本的版本库把新分支merge到master

第一步也可以直接使用git clone /d/winsegit/winse.github.com/,后面添加github网络的远程版本库remote-repo就是了。

命令

U盘数据更新提交到笔记本

$ git branch usb
$ git checkout usb
$ git add *got-git*
$ git commit -m definitive-guide-of-git

Winseliu@WINSE /i/works/winse.github.com (usb)
$ git remote add notebook /d/winsegit/winse.github.com/

Winseliu@WINSE /i/works/winse.github.com (usb)
$ git fetch notebook
From d:/winsegit/winse.github.com
 * [new branch]      master     -> notebook/master

Winseliu@WINSE /i/works/winse.github.com (usb)
$ git remote
notebook
origin

Winseliu@WINSE /i/works/winse.github.com (usb)
$ git  branch -r
  notebook/master
  origin/HEAD -> origin/master
  origin/master

Winseliu@WINSE /i/works/winse.github.com (usb)
$ git push notebook usb
Counting objects: 8, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 490 bytes | 0 bytes/s, done.
Total 5 (delta 1), reused 0 (delta 0)
To d:/winsegit/winse.github.com/
 * [new branch]      usb -> usb

笔记本合并U盘提交的数据

Winseliu@WINSE /d/winsegit/winse.github.com (master)
$ git branch
* master
  usb

Winseliu@WINSE /d/winsegit/winse.github.com (master)
$ git cherry usb

Winseliu@WINSE /d/winsegit/winse.github.com (master)
$ git merge usb
Updating 9f7dff3..31ffaa9
Fast-forward
 bookreview/_posts/2013-10-27-got-git-the-definitive-guide-of-git.md | 5 +++++
 1 file changed, 5 insertions(+)
 create mode 100644 bookreview/_posts/2013-10-27-got-git-the-definitive-guide-of-git.md

U盘重新获取笔记本的数据合并到usb分支

Winseliu@WINSE /i/works/winse.github.com (usb)
$ git fetch notebook
From d:/winsegit/winse.github.com
   9f7dff3..31ffaa9  master     -> notebook/master

Winseliu@WINSE /i/works/winse.github.com (usb)
$ git merge master
Already up-to-date.

其他实践命令

远程版本库中包含的分支

Winseliu@WINSE /i/works/winse.github.com (usb)
$ git ls-remote --heads /d/winsegit/winse.github.com
9f7dff396b357ca23e1cd765a6dae4ade3417e15        refs/heads/master

查看远程分支

Winseliu@WINSE /i/works/winse.github.com (usb)
$ git branch -r
  new-remote/master
  origin/HEAD -> origin/master
  origin/master

添加的远程版本库重命名

Winseliu@WINSE /i/works/winse.github.com (usb)
$ git remote rename new-remote notebook

Git查看远程库路径

Administrator@WINSELIU /e/git/hello-clone (master)
$ git remote -v
origin  e:/git/hello (fetch)
origin  e:/git/hello (push)

查看全部的本地引用

Winseliu@WINSE /i/works/winse.github.com (usb)
$ git show-ref
9f7dff396b357ca23e1cd765a6dae4ade3417e15 refs/heads/master
31ffaa98d45eaccf8f9d0949fc1d4375f36f9edb refs/heads/usb
06f6c285b7402fb23a50ccb929b7cd84d98028e7 refs/remotes/origin/HEAD
06f6c285b7402fb23a50ccb929b7cd84d98028e7 refs/remotes/origin/master

查看哪些提交领先(未被推送到上游跟踪分支中)

Winseliu@WINSE /i/works/winse.github.com (usb)
$ git cherry master
+ 31ffaa98d45eaccf8f9d0949fc1d4375f36f9edb

各种引用ID之间转换

Winseliu@WINSE /d/winsegit/winse.github.com (master)
$ git rev-parse usb master
31ffaa98d45eaccf8f9d0949fc1d4375f36f9edb
9f7dff396b357ca23e1cd765a6dae4ade3417e15

–END

Java反编译工具使用记录

工具

差异

JD-Core还是比较与时俱进的,对泛型/foreach等新的语法都支持。Jad则只支持到only 45.3(1.1), 46.0 and 47.0(1.3)。
任何事物都不是完美的,结合两个工具来看反编译后的源码能更好的回归源码的真相。

  • JD-Core解析双for循环是存在问题!结合jad可能更好的明白源码。
  • 内部类解析不够好,JD-Core相对错误少一些

对比

这里就[for循环]/[双层for循环]/[内部类]进行对比。

单for循环

源码

1
2
3
4
5
6
7
List<String> list = Arrays.asList("abc", "bcd");

public void testForEach() {
  for (String ele : list) { // for编译成字节码后使用iterator的形式
      System.out.println(ele);
  }
}

JD-Core v0.3.5 JD-GUI v0.6.2

1
2
3
4
5
6
List<String> list = Arrays.asList(new String[] { "abc", "bcd" });

public void testForEach() {
for (String ele : this.list)
  System.out.println(ele);
}

Jad v1.5.8e2.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public JavaDecompilerTest()
{
  list = Arrays.asList(new String[] {
      "abc", "bcd"
  });
}

public void testForEach()
{
  String ele;
  for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(ele))
      ele = (String)iterator.next();

}

List list;

双层for循环

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
{
  Map<String, String> map = new HashMap<String, String>();
  map.put("12", "23");
  list.add(map);
}

public void testForIndex() {
  for (int i = 0; i < list.size(); i++) {
      Map<String, String> map = list.get(i);
      for (String key : map.keySet())
          System.out.println(map.get(key));
  }
}

public void testForEach() {
  for (Map<String, String> map : list) {
      for (String key : map.keySet())
          System.out.println(map.get(key));
  }
}

JD-Core v0.3.5 JD-GUI v0.6.2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  List<Map<String, String>> list;

  public JavaDecompilerTest2()
  {
  this.list = new ArrayList();

  Map map = new HashMap();
  map.put("12", "23");
  this.list.add(map);
  }

  public void testForIndex() {
  for (int i = 0; i < this.list.size(); i++) {
    Map map = (Map)this.list.get(i);
    for (String key : map.keySet())
      System.out.println((String)map.get(key));
  }
  }

  public void testForEach()
  {
  Iterator localIterator2;
  for (Iterator localIterator1 = this.list.iterator(); localIterator1.hasNext(); 
    localIterator2.hasNext())
  {
    Map map = (Map)localIterator1.next();
    localIterator2 = map.keySet().iterator(); continue; String key = (String)localIterator2.next();
    System.out.println((String)map.get(key));
  }
  }

Jad v1.5.8e2.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public JavaDecompilerTest2()
{
  list = new ArrayList();
  Map map = new HashMap();
  map.put("12", "23");
  list.add(map);
}

public void testForIndex()
{
  for(int i = 0; i < list.size(); i++)
  {
      Map map = (Map)list.get(i);
      String key;
      for(Iterator iterator = map.keySet().iterator(); iterator.hasNext(); System.out.println((String)map.get(key)))
          key = (String)iterator.next();

  }

}

public void testForEach()
{
  for(Iterator iterator = list.iterator(); iterator.hasNext();)
  {
      Map map = (Map)iterator.next();
      String key;
      for(Iterator iterator1 = map.keySet().iterator(); iterator1.hasNext(); System.out.println((String)map.get(key)))
          key = (String)iterator1.next();

  }

}

List list;

内部类

源码

1
2
3
4
5
6
7
public class JavaDecompilerTest3 {

  private class Test2 {}
  
  Test2 test = new Test2();
  
}

JD-Core v0.3.5 JD-GUI v0.6.2

1
2
3
4
5
6
7
8
9
10
11
public class JavaDecompilerTest3
{
  JavaDecompilerTest3.Test2 test = new JavaDecompilerTest3.Test2(null);

  private class Test2
  {
  private Test2()
  {
  }
  }
}

Jad v1.5.8e2.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class JavaDecompilerTest3
{
  private class Test2
  {

      final JavaDecompilerTest3 this$0;

      private Test2()
      {
          this$0 = JavaDecompilerTest3.this;
          super();
      }

      Test2(Test2 test2)
      {
          this();
      }
  }


  public JavaDecompilerTest3()
  {
      test = new Test2(null);
  }

  Test2 test;
}

后记

工具javap可以查看class的方法签名,通过jd-gui和jad可以反编译得到源码,如果代码没有混淆的话,多半就能了解代码的功能了。

读jdk7的try-resource的字节码

先了解下字节码的规范:Compiling for the Java Virtual Machine

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
$ javap -public -c -v ByteCodeTest.class
Classfile /E:/test/target/test-classes/com/ByteCodeTest.class
  Last modified 2016-5-6; size 992 bytes
  MD5 checksum ee7912d638a98f9a4a61d726e08c08f0
  Compiled from "ByteCodeTest.java"
public class com.ByteCodeTest
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // com/ByteCodeTest
   #2 = Utf8               com/ByteCodeTest
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Methodref          #3.#9          // java/lang/Object."<init>":()V
   #9 = NameAndType        #5:#6          // "<init>":()V
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/ByteCodeTest;
  #14 = Utf8               tryResourceWithFinally
  #15 = Utf8               Exceptions
  #16 = Class              #17            // java/io/FileNotFoundException
  #17 = Utf8               java/io/FileNotFoundException
  #18 = Class              #19            // java/io/IOException
  #19 = Utf8               java/io/IOException
  #20 = Utf8               RuntimeVisibleAnnotations
  #21 = Utf8               Lorg/junit/Test;
  #22 = Class              #23            // java/io/FileInputStream
  #23 = Utf8               java/io/FileInputStream
  #24 = String             #25            //
  #25 = Utf8
  #26 = Methodref          #22.#27        // java/io/FileInputStream."<init>":(Ljava/lang/String;)V
  #27 = NameAndType        #5:#28         // "<init>":(Ljava/lang/String;)V
  #28 = Utf8               (Ljava/lang/String;)V
  #29 = Fieldref           #30.#32        // java/lang/System.out:Ljava/io/PrintStream;
  #30 = Class              #31            // java/lang/System
  #31 = Utf8               java/lang/System
  #32 = NameAndType        #33:#34        // out:Ljava/io/PrintStream;
  #33 = Utf8               out
  #34 = Utf8               Ljava/io/PrintStream;
  #35 = String             #36            // ing
  #36 = Utf8               ing
  #37 = Methodref          #38.#40        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #38 = Class              #39            // java/io/PrintStream
  #39 = Utf8               java/io/PrintStream
  #40 = NameAndType        #41:#28        // println:(Ljava/lang/String;)V
  #41 = Utf8               println
  #42 = Methodref          #43.#45        // java/io/InputStream.close:()V
  #43 = Class              #44            // java/io/InputStream
  #44 = Utf8               java/io/InputStream
  #45 = NameAndType        #46:#6         // close:()V
  #46 = Utf8               close
  #47 = Methodref          #48.#50        // java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V
  #48 = Class              #49            // java/lang/Throwable
  #49 = Utf8               java/lang/Throwable
  #50 = NameAndType        #51:#52        // addSuppressed:(Ljava/lang/Throwable;)V
  #51 = Utf8               addSuppressed
  #52 = Utf8               (Ljava/lang/Throwable;)V
  #53 = Utf8               in
  #54 = Utf8               Ljava/io/InputStream;
  #55 = Utf8               StackMapTable
  #56 = Utf8               SourceFile
  #57 = Utf8               ByteCodeTest.java
{
  public com.ByteCodeTest();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #8                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 10: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/ByteCodeTest;

  public void tryResourceWithFinally() throws java.io.FileNotFoundException, java.io.IOException;
    descriptor: ()V
    flags: ACC_PUBLIC
    Exceptions:
      throws java.io.FileNotFoundException, java.io.IOException
    RuntimeVisibleAnnotations:
      0: #21()
    Code:
      stack=3, locals=4, args_size=1
         0: aconst_null
         1: astore_1
         2: aconst_null
         3: astore_2
         4: new           #22                 // class java/io/FileInputStream
         7: dup
         8: ldc           #24                 // String
        10: invokespecial #26                 // Method java/io/FileInputStream."<init>":(Ljava/lang/String;)V
        13: astore_3
        14: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
        17: ldc           #35                 // String ing
        19: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        22: aload_3
        23: ifnull        66
        26: aload_3
        27: invokevirtual #42                 // Method java/io/InputStream.close:()V
        30: goto          66
        33: astore_1
        34: aload_3
        35: ifnull        42
        38: aload_3
        39: invokevirtual #42                 // Method java/io/InputStream.close:()V
        42: aload_1
        43: athrow
        44: astore_2
        45: aload_1
        46: ifnonnull     54
        49: aload_2
        50: astore_1
        51: goto          64
        54: aload_1
        55: aload_2
        56: if_acmpeq     64
        59: aload_1
        60: aload_2
        61: invokevirtual #47                 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V
        64: aload_1
        65: athrow
        66: return
      Exception table:
         from    to  target type
            14    22    33   any
             4    44    44   any
      LineNumberTable:
        line 14: 0
        line 15: 14
        line 16: 22
        line 17: 66
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      67     0  this   Lcom/ByteCodeTest;
           14      28     3    in   Ljava/io/InputStream;
      StackMapTable: number_of_entries = 6
        frame_type = 255 /* full_frame */
          offset_delta = 33
          locals = [ class com/ByteCodeTest, class java/lang/Throwable, class java/lang/Throwable, class java/io/InputStream ]
          stack = [ class java/lang/Throwable ]
        frame_type = 250 /* chop */
          offset_delta = 8
        frame_type = 65 /* same_locals_1_stack_item */
          stack = [ class java/lang/Throwable ]
        frame_type = 9 /* same */
        frame_type = 9 /* same */
        frame_type = 249 /* chop */
          offset_delta = 1
}
SourceFile: "ByteCodeTest.java"


  public void tryResourceWithFinally() throws FileNotFoundException, IOException {
    try (InputStream in = new FileInputStream("")) {
      System.out.println("ing");
    }
  }

异常eclipse提示啥直接抛出来,不要 throws Exception ,不然前面的 astore_1/astore_2 你就看不懂了!!!

解析:要看懂try-catch-finally,必须关注 Exception table

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
any a1 = null
any a2 = null
any a3/in = new FileInputStream("")

System.out.println("ing")

  catch-1(33):
  // noop
  if(a3/in != null){
  in.close()
  }
  rethrow a1

if(a3/in != null){
in.close()
}

catch-2(44):
// noop
if(a3/in != null){
in.close()
}
if(a1 == null){
  // noop
  a1 = a2
  rethrow a1
} 

if (a1 == a2){
  rethrow a1
} 

a1.addSuppressed(a2)
rethrow a1

在添加自定义的finally:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
$ javap -public -c ByteCodeTest.class
Compiled from "ByteCodeTest.java"
public class com.ByteCodeTest {
  public com.ByteCodeTest();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public void tryResourceWithFinally() throws java.io.FileNotFoundException, java.io.IOException;
    Code:
       0: aconst_null
       1: astore_1
       2: aconst_null
       3: astore_2
       4: new           #22                 // class java/io/FileInputStream
       7: dup
       8: ldc           #24                 // String
      10: invokespecial #26                 // Method java/io/FileInputStream."<init>":(Ljava/lang/String;)V
      13: astore_3
      14: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      17: ldc           #35                 // String ing
      19: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      22: aload_3
      23: ifnull        79
      26: aload_3
      27: invokevirtual #42                 // Method java/io/InputStream.close:()V
      30: goto          79
      33: astore_1
      34: aload_3
      35: ifnull        42
      38: aload_3
      39: invokevirtual #42                 // Method java/io/InputStream.close:()V
      42: aload_1
      43: athrow
      44: astore_2
      45: aload_1
      46: ifnonnull     54
      49: aload_2
      50: astore_1
      51: goto          64
      54: aload_1
      55: aload_2
      56: if_acmpeq     64
      59: aload_1
      60: aload_2
      61: invokevirtual #47                 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V
      64: aload_1
      65: athrow
      66: astore        4
      68: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      71: ldc           #53                 // String finish
      73: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      76: aload         4
      78: athrow
      79: getstatic     #29                 // Field java/lang/System.out:Ljava/io/PrintStream;
      82: ldc           #53                 // String finish
      84: invokevirtual #37                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      87: return
    Exception table:
       from    to  target type
          14    22    33   any
           4    44    44   any
           0    66    66   any
}


  public void tryResourceWithFinally() throws FileNotFoundException, IOException {
    try (InputStream in = new FileInputStream("")) {
      System.out.println("ing");
    } finally {
      System.out.println("finish");
    }
  }

在异常表里面多了一条记录,比上面的复杂点。

–END

让敲Shell命令高效起来

在刚上班的时刻,做过程序的部署工作,后面尽管工作中直接接触的机会很少。 但是一直对shell很敬(很牛)畏(太强太多),第一使用起来确实不是看几本书就能用好的,需要经常持久的使用,第二嘛命令太多个不用一段时间基本就忘记了。

来到新公司后,主要是后台代码的开发。尽管和部署挂不上什么关系,但再次遇到总有个想头-原来使用过去查查,算是自己使用linux过程中的一点总结。

记住历史,温故而知新

如果说是新人,可以通过历史学习前辈使用的命令。 作为维护人员,可以记录操作的命令,修改原有命令的部分再执行。

命令 解释
history
!! 执行上一条命令
!blah 执行最近的以 blah 开头的命令,如 !ls
!blah:p 仅打印输出,而不执行
!$ 上一条命令的最后一个参数,与 Alt + . 相同
!$:p 打印输出 !$ 的内容
!* 上一条命令的所有参数
!*:p 打印输出 !* 的内容
^blah 删除上一条命令中的 blah
^blah^foo 将上一条命令中的 blah 替换为 foo
^blah^foo^ 将上一条命令中所有的 blah 都替换为 foo
fc 打开编辑器(vim)编辑上一条命令
fc 123 编辑命令历史中编号为123的命令
fc 123 130 编辑命令历史中123-130的八条命令,退出后依次执行
fc ls 编辑最后一条以ls开头的命令
fc -s ls=cat ls 将最后一条以ls开头的命令中的ls替换成cat,然后执行
1
2
mkdir mmm
cd $*

参考 bash命令行历史的用法

快捷键

快捷方式

当遇到一串很长的路径时,如果每次都输入,尽管有Tab的辅助,但也不是一件烦心的事情。 这时,我们可以根据增加快捷方式/重定位为我们的工作提高效率,减少重复无谓的工作。

alias datanodelog="less ~/hadoop/logs/hadoop-Winseliu-datanode-WINSE.log"
alias jobtrackerlog="less ~/hadoop/logs/hadoop-Winseliu-jobtracker-WINSE.log"
alias tasktrackerlog="less ~/hadoop/logs/hadoop-Winseliu-tasktracker-WINSE.log"

ln -s /cygdrive/d/groovy-1.8.4/ groovylink

当你去看linux的bash脚本时,你会发现发现ll的命令其实是ls -l的alias的别名而已。 在工作中如果发现很多类似重复的操作,赶紧的把alias用起来的吧!

快速定位

快捷 解释
编辑命令
Ctrl + a 移到命令行首
Ctrl + e 移到命令行尾
Ctrl + f 按字符前移(右向)
Ctrl + b 按字符后移(左向)
Alt + f 按单词前移(右向)
Alt + b 按单词后移(左向)
Ctrl + xx 在命令行首和光标之间移动
Ctrl + u 从光标处删除至命令行首
Ctrl + k 从光标处删除至命令行尾
Ctrl + w 从光标处删除至字首
Alt + d 从光标处删除至字尾
Ctrl + d 删除光标处的字符
Ctrl + h 删除光标前的字符
Ctrl + y 粘贴至光标后
Alt + c 从光标处更改为首字母大写的单词
Alt + u 从光标处更改为全部大写的单词
Alt + l 从光标处更改为全部小写的单词
Ctrl + t 交换光标处和之前的字符
Alt + t 交换光标处和之前的单词
Alt + Backspace 与 Ctrl + w 相同类似,分隔符有些差别
重新执行命令
Ctrl + r 逆向搜索命令历史
Ctrl + g 从历史搜索模式退出
Ctrl + p 历史中的上一条命令,感觉不用那么麻烦吧,直接方向键就行了啊!
控制命令
Ctrl + l 清屏
Ctrl + o 执行当前命令,并选择上一条命令
Ctrl + s 阻止屏幕输出
Ctrl + q 允许屏幕输出
Ctrl + c 终止命令
Ctrl + z 挂起命令

参考 Bash快捷键,让命令更有效率

使用趁手的工具

看到同事使用WinScp定位到目录上传文件,然后使用Putty进行命令操作,那个辛苦啊,甚是麻烦! SSH Secure Shell则集成了Putty和WinScp的功能。 更甚者还是用Xmanger的图形化界面: Windows连接Linux的常用工具Windows下如何远程连接 Linux

推荐我最爱的SSH工具: SecureCRT

SecureCRT不但能满足shell命令,能保存基本上全部的操作过程(Putty操作则和Linux上的终端效果一样)。

  • 选择复制,右键粘贴的功能也相当高效。
  • 基于zmoden的lrzsz命令能实现文件的上传和下载功能。
  • 记住密码这功能不在话下。
  • 克隆到新窗口中,实现多视图同时编辑。
1
2
alias rz="rz -e"
 

看到网上说的Xshell功能和SecureCRT类似,还支持颜色,并且是开源的没有版权问题!。Xshell讨论

配合screen命令更好用: https://www.ibm.com/developerworks/cn/linux/l-cn-screen/index.html

一些点

  • /etc/profile.d/jdk.sh

使用具体案例

  1. 批量改名加后缀:
1
ls -1 | xargs -i mv {}{,.old}

还原:

1
$ ls -1 | while read line ; do mv "$line" "${line%.*}" ; done
  1. 花括号展开

可能最奇怪的展开是花括号展开。通过它,你可以从一个包含花括号的模式中 创建多个文本字符串。这是一个例子:

1
2
3
4
5
[me@linuxbox ~]$ echo Front-{A,B,C}-Back
[me@linuxbox ~]$ echo Number_{1..5}
[me@linuxbox ~]$ echo {Z..A}
[me@linuxbox ~]$ echo a{A{1,2},B{3,4}}b
[me@linuxbox Pics]$ mkdir {2007..2009}-0{1..9} {2007..2009}-{10..12}
  1. bash提取

  2. https://my.oschina.net/psuyun/blog/357840

  3. http://m.jb51.net/article/64804.htm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
file=/dir1/dir2/dir3/my.file.txt
我们可以用 ${ } 分别替换获得不同的值:
${file#*/}:拿掉第一条 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt
${file##*/}:拿掉最后一条 / 及其左边的字符串:my.file.txt
${file#*.}:拿掉第一个 . 及其左边的字符串:file.txt
${file##*.}:拿掉最后一个 . 及其左边的字符串:txt
${file%/*}:拿掉最后条 / 及其右边的字符串:/dir1/dir2/dir3
${file%%/*}:拿掉第一条 / 及其右边的字符串:(空值)
${file%.*}:拿掉最后一个 . 及其右边的字符串:/dir1/dir2/dir3/my.file
${file%%.*}:拿掉第一个 . 及其右边的字符串:/dir1/dir2/dir3/my

- # 是去掉左边(在鉴盘上 # 在 $ 之左边)
- % 是去掉右边(在鉴盘上 % 在 $ 之右边)
- 单一符号是最小匹配﹔两个符号是最大匹配。

${file:0:5}:提取最左边的 5 个字节:/dir1
${file:5:5}:提取第 5 个字节右边的连续 5 个字节:/dir2

我们也可以对变量值里的字符串作替换:

${file/dir/path}:将第一个 dir 提换为 path:/path1/dir2/dir3/my.file.txt
${file//dir/path}:将全部 dir 提换为 path:/path1/path2/path3/my

利用 ${ } 还可针对不同的变数状态赋值(沒设定、空值、非空值):
${file-my.file.txt} :假如 $file 沒有设定,則使用 my.file.txt 作传回值。(空值及非空值時不作处理) 
${file:-my.file.txt} :假如 $file 沒有設定或為空值,則使用 my.file.txt 作傳回值。 (非空值時不作处理)
${file+my.file.txt} :假如 $file 設為空值或非空值,均使用 my.file.txt 作傳回值。(沒設定時不作处理)
${file:+my.file.txt} :若 $file 為非空值,則使用 my.file.txt 作傳回值。 (沒設定及空值時不作处理)
${file=my.file.txt} :若 $file 沒設定,則使用 my.file.txt 作傳回值,同時將 $file 賦值為 my.file.txt 。 (空值及非空值時不作处理)
${file:=my.file.txt} :若 $file 沒設定或為空值,則使用 my.file.txt 作傳回值,同時將 $file 賦值為my.file.txt 。 (非空值時不作处理)
${file?my.file.txt} :若 $file 沒設定,則將 my.file.txt 輸出至 STDERR。 (空值及非空值時不作处理)
${file:?my.file.txt} :若 $file 没设定或为空值,则将 my.file.txt 输出至 STDERR。 (非空值時不作处理)

${#var} 可计算出变量值的长度:
${#file} 可得到 27 ,因为/dir1/dir2/dir3/my.file.txt 是27个字节

SSH登录

一般ROOT都是禁用远程登录的,但是内网开放其实没所谓。可以通过 匹配特定的规则 开放,或者通过其他方式登录 PermitRootLogin without-password

http://serverfault.com/questions/189574/allow-root-login-from-one-ip-address-only

1
2
3
4
5
6
7
# Authentication:
...
PermitRootLogin no 
...
# Example of overriding settings on a per-user basis
Match Address 192.168.0.214
        PermitRootLogin yes

加快SSH登录:multiplexing

controlpersist 多个连接到相同主机的SSH会话将会共享相同的TCP连接。这样,接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
~/.ssh/config
Host myserver.example.com
  ControlMaster auto
  ControlPath /tmp/%r@%h:%p
  ControlPersist 10m
# 其他参数
  User            soulteary
  Hostname        10.11.12.240
  Port            22
  IdentityFile    ~/.ssh/keys/2022
  ControlPath     ~/.ssh/home-xh-%r@%h:%p
  ControlPersist  yes
  TCPKeepAlive    yes
  Compression     yes
  ForwardAgent    yes

可以使用-O check 以及 -O exit参数类中断主连接。

Screen

无惧网络风险,时时交互式的nohup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
screen
screen ls 
screen -r $PID
screen -d -r $PID

screen -X -S [session # you want to kill] quit/kill
screen -ls | grep detached | cut -d. -f1 | awk '{print $1}' | xargs kill
pkill screen

Once connected to the session press Ctrl + A then type :quit

//Creation:
screen -S some_name proc
// Kill detached session
screen -S some_name -X quit

screen -wipe
Should clean all dead screen sessions.

VI

1
2
3
4
ctrl+f          向前翻页
ctrl+b          向后翻页
ctrl+d          向前翻半页
ctrl+u          向后翻半页 

tree

sudo

1
echo "`whoami` ALL=(ALL) NOPASSWD:ALL" | sudo tee "/etc/sudoers.d/dont-prompt-$USER-for-sudo-password"

zsh

如果Linux作为日常使用机器。

监控

glances, htop, iftop iotop bmon dstat, vim jq, tmux screen

大文件

1
2
3
4
5
6
7
8
9
10
split -b=1M -d  file.txt file 

split -l 100 input_file output_file

split --bytes=1M /path/to/image/image.jpg /path/to/image/prefixForNewImagePieces
cat prefixFiles* > newimage.jpg

$ split --bytes 500M --numeric-suffixes --suffix-length=3 foo foo.
$ split -b 100k -d -a 3 foo foo.
$ cat foo.* > foo_2

虚拟内存

收藏

–END

学习Linux资源

最近听了Teahour.fm的【25集-和又拍云UpYun的邵海扬聊运维】。 第一次听到了linux三剑客(bash,sed,awk)的概念,但感觉相当亲切。

接触Linux断断续续加起来也有2年的时间。

书籍

除了遇到具体问题Google外,同时得益于大.家的书籍,强烈的推荐下面的4本书:

  1. Shell脚本学习指南
  2. sed与awk(第二版)
  3. Shell十三问
  4. 学习VI和VIM编辑器

每本都是经典,每读一遍都能从中学习到新的东西。

学Linux的笔记:

  1. http://su1216.iteye.com/blog/1940429

–END

Tomcat源码阅读-环境搭建

很早就买了《深入剖析Tomcat》这本书,但是一直没有下定决心去看tomcat的源码
在工作中大部分时间都是使用tomcat作为容器,整体来说对tomcat还是有所了解,有那么点好奇,还是想好好的深入的了解下Tomcat。

既然要读源码,第一步就是检出源码,配置环境。

下载源码

打开Eclipse的git视图,下载源码https://github.com/apache/tomcat.git 然后检出TOMCAT_7_0_42的Tag。

生成eclipse的工程文件

执行Ant的Target为ide-eclipse任务。正常完成后,会在tomcat工作目录下生成eclipse工程需要的.project和.classpath两个文件。

D:\top_projects\tomcat>ant ide-eclipse
...
downloadfile:
    [mkdir] Created dir: D:\usr\share\java\wsdl4j-1.6.2
      [get] Getting: http://repo.maven.apache.org/maven2/wsdl4j/wsdl4j/1.6.2/wsdl4j-1.6.2.jar
      [get] To: D:\usr\share\java\wsdl4j-1.6.2\wsdl4j-1.6.2.jar
     [copy] Copying 1 file to D:\top_projects\tomcat\output\extras\webservices
     [copy] Copying 1 file to D:\top_projects\tomcat\output\extras\webservices

ide-eclipse:
     [copy] Copying 1 file to D:\top_projects\tomcat
     [copy] Copying 1 file to D:\top_projects\tomcat
     [echo] Eclipse project files created.
     [echo] Read the Building page on the Apache Tomcat documentation site for details on how to configure your Eclipse
workplace.

BUILD SUCCESSFUL
Total time: 2 minutes 47 seconds

在Git Repositories视图,右键Working Directory节点,然后选择Import Projects到eclipse工作区即可。

依赖jar处理

在导入为eclipse工程后,出现了ANT_HOME和TOMCAT_LIBS_BASE的classpath依赖的错误,导致整个工程不能编译
在生成eclipse工程文件的步骤时,有下载编译依赖的jar,我们需要把这些jar路径告诉eclipse-classpath

选择Preferences -> Java -> Build Path -> Classpath Variables添加ANT_HOME和TOMCAT_LIBS_BASE的两个路径。

其中TOMCAT_LIBS_BASE为build.properties.default文件中base.path指定的路径; 确定后即可找到依赖的jar。

小结

Tomcat的开发环境的搭建,由于提供了Ant的脚本,所以配置还是比较简单。需要注意的就是配置两个额外eclipse的classpath参数即可。 搭建好了环境,下一篇穿插讲讲是脚本的启动。这样才知道Tomcat是调用哪个主类来启动Tomcat系统的!