Roc`s 随想录

诚信,认真,专注,踏实


  • 首页

  • 分类

  • 标签

  • 归档

  • 关于

Thread类与多线程

发表于 2015-04-07   |   分类于 Java基础   |     |   阅读次数

首先是ThreadA类,继承了Thread,重写了run().

package cn.wiz.roc.thread;

public class ThreadA extends Thread {
    public ThreadA(String name) {
        super(name);
    }

    public synchronized void run() {
        try {
            for (int i = 0; i < 100; i++) {
                System.out.println(this.getName() + ":" + i);
                if (i % 3 == 0)
                    //每隔3的时候线程休眠1000ms
                    Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

ThreadB类似:

package cn.wiz.roc.thread;

public class ThreadB extends Thread {
    public ThreadB(String name) {
        super(name);
    }

    public synchronized void run() {
        try {
            for (int i = 0; i < 100; i++) {
                System.out.println(this.getName() + ":" + i);
                // i能被4整除时,休眠100毫秒
                if (i % 4 == 0)
                    Thread.sleep(1500);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

SleepTest.java

package cn.wiz.roc.thread;

public class SleepTest {
    public static void main(String[] args) {
        ThreadA t1 = new ThreadA("A");
        ThreadB t2 = new ThreadB("B");
        t1.start();
        t2.start();
    }
}

其中一段执行结果:

...
A:16
A:17
A:18
A:19
A:20
A:21
B:17
B:18
B:19
B:20
...

对于多线程环境,start()方法会通过底层的API执行重写的run()方法,使该方法获得竞争CPU计算的能力。在方法的执行过程中,原来的调用环境依次往下执行,不会等待run()方法执行结束。
run()的过程里,可以调用Thread.sleep(1000);使得线程休眠。当然,Thread还有其他几个方法,在此不再赘述。
–Roc


Thread.sleep()和Thread.currentThread().sleep()区别

线程可以用继承Thread类或者实现Runnable接口来实现.

Thread.sleep()是Thread类的方法,只对当前线程起作用,睡眠一段时间.

如果线程是通过继承Thread实现的话这2个方法没有区别;

如果线程是通过实现Runnable接口来实现的,则不是Thread类,不能直接使用Thread.sleep()

必须使用Thread.currentThread()来得到当前线程的引用才可以调用sleep(),

所以要用Thread.currentThread().sleep()来睡眠…

Today`s Knowledge about Java

发表于 2015-04-07   |   分类于 Java基础   |     |   阅读次数

GC机制,对象生命周期等。

http://blog.csdn.net/ithomer/article/details/6252552
http://jbutton.iteye.com/blog/1569737

深入理解java内存模型系列文章

JVM内存模型及垃圾收集策略解析

网络不好的时候千万不要更新Maven仓库的依赖。很恶心

YAML格式简介

发表于 2015-04-07   |   分类于 知识记录   |     |   阅读次数

1. 概念

YAML是一种人们可以轻松阅读的数据序列化格式,并且它非常适合对动态编程语言中使用的数据类型进行编码。YAML是YAML Ain't Markup Language简写,和GNU(“GNU’s Not Unix!”)一样,YAML是一个递归着说“不”的名字。不同的是,GNU对UNIX说不,YAML说不的对象是XML。YAML不是XML。它可以用作数据序列,配置文件,log文件,Internat信息和过滤。

2. 优点

  • YAML的可读性好
  • YAML和脚本语言的交互性好
  • YAML使用实现语言的数据类型
  • YAML有一个一致的信息模型
  • YAML易于实现

3. YAML的适用范围

由于实现简单,解析成本很低,YAML特别适合在脚本语言中使用。列一下现有的语言实现:Ruby,Java,Perl,Python,PHP,OCaml,JavaScript。除了Java,其他都是脚本语言.
YAML比较适合做序列化。因为它是宿主语言数据类型直转的。
YAML做配置文件也不错。比如Ruby on Rails的配置就选用的YAML。对ROR而言,这很自然,也很省事。
由于兼容性问题,不同语言间的数据流转建议现在不要用YAML.

4. YAML不足

YAML和XML不同,没有自己的数据类型的定义,而是使用实现语言的数据类型。这一点,有可能是出奇制胜的地方,也可能是一个败笔。如果兼容性保证的不好的话,YAML数据在不同语言间流转会有问题。
假如兼容性没问题的话,YAML就太完美了。轻巧,敏捷,高效,简便,通用。

5. JYaml简介

JYAML是YAML的Java实现。
YAML使用实现语言的数据类型。我们看一下一些JYaml支持的Java数据类型:
原始数据和封装类(比如int,java.lang.Integer)
JavaBean兼容对象(Structure支持)
Collection (sequence支持)
List
Set
Map (map支持)
Arrays (sequence支持)
BigInteger 和BigDecimal
Date
注:我把我个人认为较好的文章推荐如下,方便我们共同学习和交流。
参考文献:
1 《YAML 简介》 http://www.ibm.com/developerworks/cn/xml/x-cn-yamlintro/index.html
2 《YAML 对 XML 的改进》http://www.ibm.com/developerworks/cn/xml/x-matters/part23/
3 http://jyaml.sourceforge.net/
4 http://www.yaml.org/

java中foreach与iterator迭代器

发表于 2015-04-07   |   分类于 Java基础   |     |   阅读次数

Iterator迭代器是java的一个接口,这是在JDK1.8的源代码,其中包含boolean hasNext(),E next(),default void remove(),default void forEachRemaining(Consumer<? super E> action)四个方法,两个已经是default关键字修饰的实现。

package java.util;

import java.util.function.Consumer;

public interface Iterator<E> {
    boolean hasNext();

    E next();

    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

    /**
     * @since 1.8
     */
    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

注意:在默认实现里,迭代器不支持删除。如果需要支持,需要自己实现。例如在LinkedList里边,源代码如下:

private class ListItr implements ListIterator<E> {
    private Node<E> lastReturned;
    private Node<E> next;
    private int nextIndex;
    private int expectedModCount = modCount;

    //...

    public boolean hasNext() {
        return nextIndex < size;
    }

    public E next() {
        checkForComodification();
        if (!hasNext())
            throw new NoSuchElementException();

        lastReturned = next;
        next = next.next;
        nextIndex++;
        return lastReturned.item;
    }





    public void remove() {
        checkForComodification();
        if (lastReturned == null)
            throw new IllegalStateException();

        Node<E> lastNext = lastReturned.next;
        unlink(lastReturned);
        if (next == lastReturned)
            next = lastNext;
        else
            nextIndex--;
        lastReturned = null;
        expectedModCount++;
    }

    public void set(E e) {
        if (lastReturned == null)
            throw new IllegalStateException();
        checkForComodification();
        lastReturned.item = e;
    }

    public void add(E e) {
        checkForComodification();
        lastReturned = null;
        if (next == null)
            linkLast(e);
        else
            linkBefore(e, next);
        nextIndex++;
        expectedModCount++;
    }

    public void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (modCount == expectedModCount && nextIndex < size) {
            action.accept(next.item);
            lastReturned = next;
            next = next.next;
            nextIndex++;
        }
        checkForComodification();
    }

    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

下面是网上的其他解释,更能从本质上解释原因:
Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。

  • 集合迭代时对集合进行修改抛ConcurrentModificationException原因的深究以及解决方案

AES加密

发表于 2015-04-07   |   分类于 数学和算法   |     |   阅读次数

加密的历程:

从 按规则替换 -> 对称加密 -> 非对称加密 的过程,看到加密技术的不断进化。

破解方式:

按规则替换:根据频率破解。
对称加密:截获密钥。
非对称加密:???

非对称加密:

非对称加密又称公开密钥加密。

公开密钥加密(英语:public-key cryptography,又译为公开密钥加密),也称为非对称加密(asymmetric cryptography),一种密码学算法类型,在这种密码学方法中,需要一对密钥,一是个私人密钥,另一个则是公开密钥。这两个密钥是数学相关,用某用户密钥加密后所得的信息,只能用该用户的解密密钥才能解密。如果知道了其中一个,并不能计算出另外一个。因此如果公开了一对密钥中的一个,并不会危害到另外一个的秘密性质。称公开的密钥为公钥;不公开的密钥为私钥。
–wiki

在非对称加密中使用的主要算法有:RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)等。

优点

与对称密钥加密相比,优点在于无需共享的通用密钥,解密的私钥不发往任何用户。即使公钥在网上被截获,如果没有与其匹配的私钥,也无法解密,所截获的公钥是没有任何用处的。

过程

假设两个用户A向B发送信息。B的公钥为c,对应私钥(也是属于B的)为d,明文为x.

  1. A用公钥对明文进行加密形成密文c(x),然后传输密文;
  2. B收到密文,用私钥对密文进行解密d(c(x)),得到要通信的明文x。
    B向A发送信息反之。

现在主要解释RSA加密原理。


原理

互质关系

如果两个正整数,除了1以外,没有其他公因子,我们就称这两个数是互质关系(coprime)。比如,15和32没有公因子,所以它们是互质关系。这说明,不是质数也可以构成互质关系。

有以上,不难得到以下结论:

  1. 任意两个质数构成互质关系,比如13和61。
  2. 一个数是质数,另一个数只要不是前者的倍数,两者就构成互质关系,比如3和10。
  3. 如果两个数之中,较大的那个数是质数,则两者构成互质关系,比如97和57。
  4. 1和任意一个自然数是都是互质关系,比如1和99。
  5. p是大于1的整数,则p和p-1构成互质关系,比如57和56。
  6. p是大于1的奇数,则p和p-2构成互质关系,比如17和15。

欧拉函数

请思考一下问题:

任意给定正整数n,请问在小于等于n的正整数之中,有多少个与n构成互质关系?(比如,在1到8之中,有多少个数与8构成互质关系?)
–阮一峰

计算这个值的方法就叫做欧拉函数,以φ(n)表示。在1到8之中,与8形成互质关系的是1、3、5、7,所以 φ(n) = 4。
φ(n) 的计算方法并不复杂,但是为了得到最后那个公式,需要一步步讨论。

第一种情况

如果n=1,则 φ(1) = 1 。因为1与任何数(包括自身)都构成互质关系。

第二种情况

如果n是质数,则 φ(n)=n-1 。因为质数与小于它的每一个数,都构成互质关系。比如5与1、2、3、4都构成互质关系。

第三种情况

如果n是质数的某一个次方,即 n = p^k (p为质数,k为大于等于1的整数),则
$$\phi(p^k)=p^k-p^{k-1}$$
比如 φ(8) = φ(2^3) =2^3 - 2^2 = 8 -4 = 4。
这是因为只有当一个数不包含质数p,才可能与n互质。而包含质数p的数一共有p^(k-1)个,即1×p、2×p、3×p、…、p^(k-1)×p,把它们去除,剩下的就是与n互质的数。
上面的式子还可以写成下面的形式:
$$\phi(p^k)=p^k-p^{k-1}=p^k(1-\frac{1}{p})$$
可以看出,上面的第二种情况是 k=1 时的特例。

第四种情况

如果n可以分解成两个互质的整数之积,
$$n=p_1p_2$$
则
$$\phi(n)=\phi(p_1p_2)=\phi(p_1)\phi(p_2)$$
即积的欧拉函数等于各个因子的欧拉函数之积。比如,*φ(56)=φ(8×7)=φ(8)×φ(7)=4×6=24
。
这一条的证明要用到”中国剩余定理”,这里就不展开了,只简单说一下思路:如果a与p1互质(a<p1),b与p2互质(b<p2),c与p1p2互质(c<p1p2),则c与数对 (a,b) 是一一对应关系。由于a的值有φ(p1)种可能,b的值有φ(p2)种可能,则数对 (a,b) 有φ(p1)φ(p2)种可能,而c的值有φ(p1p2)种可能,所以φ(p1p2)就等于φ(p1)φ(p2)。

第五种情况

待续…

—未完待续:http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html

java多线程中的volatile

发表于 2015-04-07   |   分类于 Java基础   |     |   阅读次数

volatile:
英[‘vɒlətaɪl] 美[ˈvɑlətl, -ˌtaɪl]
adj. 易变的,不稳定的;(液体或油)易挥发的;爆炸性的;快活的,轻快的
[例句]A volatile political system makes these reforms hard to achieve.
而反复无常的政治体系又让这些方面的改革无法实施。
–xx翻译

一、volatile简述

Java 语言提供了一种稍弱的同步机制,即 volatile 变量.用来确保将变量的更新操作通知到其他线程,保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新. 当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的.

二、 volatile线程安全?

volatile 变量对所有线程是立即可见的,对 volatile 变量所有的写操作都能立即反应到其他线程之中,换句话说:volatile 变量在各个线程中是一致的,所以基于 volatile 变量的运算是线程安全的.

这句话论据貌似没有错,论点确实错的.

三、 valotile 为什么是线程不安全的?

public class VolatileTest{

    public static volatile int  i;

    public static void increase(){
        i++;
    }
}

编译(javap -c -l VolatileTest.class)后,

public class VolatileTest {
  public static volatile int i;

  public VolatileTest();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        
    LineNumberTable:
      line 1: 0

  public static void increase();
    Code:
       0: getstatic     #2                  // Field i:I, 把i的值取到了操作栈顶,volatile保证了i值此时是正确的. 
       3: iconst_1      
       4: iadd                              // increase,但其他线程此时可能已经把i值加大了好多
       5: putstatic     #2                  // Field i:I ,把这个已经out of date的i值同步回主内存中,i值被破坏了.
       8: return        
    LineNumberTable:
      line 6: 0
      line 7: 8
}

从这个角度说 volatile 并不完全是线程安全的.

四、 常见的用法

在Java内存模型中,有main memory,每个线程也有自己的memory (例如寄存器)。为了性能,一个线程会在自己的memory中保持要访问的变量的副本。这样就会出现同一个变量在某个瞬间,在一个线程的memory中的值可能与另外一个线程memory中的值,或者main memory中的值不一致的情况。
一个变量声明为volatile,就意味着这个变量是随时会被其他线程修改的,因此不能将它cache在线程memory中。以下例子展现了volatile的作用:

public class StoppableTask extends Thread {
    private volatile boolean pleaseStop;

    public void run() {
        while (!pleaseStop) {
            // do some stuff...
        }
    }

    public void tellMeToStop() {
        pleaseStop = true;
    }
}

假如pleaseStop没有被声明为volatile,线程执行run的时候检查的是自己的副本,就不能及时得知其他线程已经调用tellMeToStop()修改了pleaseStop的值。

Volatile一般情况下不能代替sychronized,因为volatile不能保证操作的原子性,即使只是i++,实际上也是由多个原子操作组成:read i; inc; write i,假如多个线程同时执行i++,volatile只能保证他们操作的i是同一块内存,但依然可能出现写入脏数据的情况。如果配合Java 5增加的atomic wrapper classes,对它们的increase之类的操作就不需要sychronized。

利用暗时间

发表于 2015-04-07   |   分类于 思维改变生活   |     |   阅读次数

专注,才会把事情做好。

对比在学校中,工作的时候无疑是很多打扰人的事情,常常会使效率降低。

专注,就是将某种任务的CPU优先级提高,时刻提醒自己最重要的事情是什么。

流体验,很久没有这种感觉了。

记得自己的梦想,然后时刻调整自己的思想。

对,知乎会打开自己的思路;但是,也会占用大量时间,有时候这些时间用来思考更重要。

减少任务切换。


充足的能量 保证思考所需。

http://blog.csdn.net/chuanchuan608/article/details/17915959

表、栈和队列-数据结构与算法

发表于 2015-04-07   |   分类于 数学和算法   |     |   阅读次数

第3章 表、栈和队列

3.3 Java Collection API中的表

3.3.1 Collection接口

3.3.2 Iterator接口

3.3.3 List接口、ArrayList类和LinkedList类

3.3.5关于ListIterator接口

3.4 ArrayList类的实现

  1. 基本类
  2. 迭代其、Java嵌套类和内部类

3.5 LinkedList类的实现

3.6 栈ADT

  1. 栈模型
  2. 栈的实现
  3. 应用
    • 平衡符号
    • 后缀表达式
    • 方法调用

3.7 队列ADT

  1. 队列模型
  2. 队列的数组实现
  3. 队列的应用

小结

表、栈和队列或许是在全部计算机科学重视三个基本的数据结构,大量的例子证明了他们广泛的用途。 特别的,我们看到栈是如何用来记录过程和方法调用的,以及递归是如何实现的。这对我们的理解非常重要,其原因不只因为它使得过程语言成为可能,而且还因为知道递归的实现从而消除了围绕其使用的大量谜团。
–《教科书》

做课后习题

Linux Shell入门

发表于 2015-04-07   |   分类于 Linux基础   |     |   阅读次数

Shell简介:什么是Shell,Shell命令的两种执行方式

Shell本身是一个用C语言编写的程序,它是用户使用Unix/Linux的桥梁,用户的大部分工作都是通过Shell完成的。Shell既是一种命令语言,又是一种程序设计语言。

可以说,shell使用的熟练程度反映了用户对Unix/Linux使用的熟练程度。

Shell有两种执行命令的方式:

  • 交互式(Interactive):解释执行用户的命令,用户输入一条命令,Shell就解释执行一条。
  • 批处理(Batch):用户事先写一个Shell脚本(Script),其中有很多条命令,让Shell一次把这些命令执行完,而不必一条一条地敲命令。

Shell脚本和编程语言很相似,也有变量和流程控制语句,但Shell脚本是解释执行的,不需要编译,Shell程序从脚本中一行一行读取并执行这些命令,相当于一个用户把脚本中的命令一行一行敲到Shell提示符下执行。

Shell初学者请注意,在平常应用中,建议不要用 root 帐号运行 Shell 。作为普通用户,不管您有意还是无意,都无法破坏系统;但如果是 root,那就不同了,只要敲几个字母,就可能导致灾难性后果。

几种常见的Shell

Unix/Linux上常见的Shell脚本解释器有bash、sh、csh、ksh等,习惯上把它们称作一种Shell。我们常说有多少种Shell,其实说的是Shell脚本解释器。

其中:sh
sh 由Steve Bourne开发,是Bourne Shell的缩写,sh 是Unix 标准默认的shell。

第一个Shell脚本(Shell的HelloWorld)
打开文本编辑器,新建一个文件,扩展名为sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好,如果你用php写shell 脚本,扩展名就用php好了。

输入一些代码:

#!/bin/bash
echo "Hello World !"

“#!” 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种Shell。echo命令用于向窗口输出文本。

作为可执行程序

将上面的代码保存为test.sh,并 cd 到相应目录:

chmod +x ./test.sh  #使脚本具有执行权限
./test.sh  #执行脚本

注意,一定要写成./test.sh,而不是test.sh。运行其它二进制的程序也一样,直接写test.sh,linux系统会去PATH里寻找有没有叫test.sh的,而只有/bin, /sbin, /usr/bin,/usr/sbin等在PATH里,你的当前目录通常不在PATH里,所以写成test.sh是会找不到命令的,要用./test.sh告诉系统说,就在当前目录找。

通过这种方式运行bash脚本,第一行一定要写对,好让系统查找到正确的解释器。

这里的”系统”,其实就是shell这个应用程序(想象一下Windows Explorer),但我故意写成系统,是方便理解,既然这个系统就是指shell,那么一个使用/bin/sh作为解释器的脚本是不是可以省去第一行呢?是的。

再看一个例子。下面的脚本使用 read 命令从 stdin 获取输入并赋值给 PERSON 变量,最后在 stdout 上输出:

#!/bin/bash
# Author : mozhiyan
# Copyright (c) http://see.xidian.edu.cn/cpp/linux/
# Script follows here:
echo "What is your name?"
read PERSON
echo "Hello, $PERSON"

运行脚本:

chmod +x ./test.sh
$./test.sh
What is your name?
mozhiyan
Hello, mozhiyan
$

Shell变量:Shell变量的定义、删除变量、只读变量、变量类型

定义变量

定义变量时,变量名不加美元符号($),如:

variableName="value"

注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:

  • 首个字符必须为字母(a-z,A-Z)。
  • 中间不能有空格,可以使用下划线(_)。
  • 不能使用标点符号。
  • 不能使用bash里的关键字(可用help命令查看保留关键字)。

变量定义举例:

myUrl="http://see.xidian.edu.cn/cpp/linux/"
myNum=100

使用变量
使用一个定义过的变量,只要在变量名前面加美元符号($)即可,如:

your_name="mozhiyan"
echo $your_name
echo ${your_name}

变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:

for skill in Ada Coffe Action Java 
do
    echo "I am good at ${skill}Script"
done

如果不给skill变量加花括号,写成

echo "I am good at $skillScript"`

解释器就会把$skillScript当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。

推荐给所有变量加上花括号,这是个好的编程习惯。

重新定义变量

只读变量

readonly myUrl

删除变量

unset variable_name

变量类型

运行shell时,会同时存在三种变量:

  1. 局部变量
    局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。

  2. 环境变量
    所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。

  3. shell变量
    shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行

Shell特殊变量:Shell $0, $#, $*, $@, $?, $$和命令行参数

Shell替换:Shell变量替换,命令替换,转义字符

Shell运算符:Shell算数运算符、关系运算符、布尔运算符、字符串运算符等

if [ $a -le $b ]
then
   echo "$a -le $b: a is less or  equal to b"
else
   echo "$a -le $b: a is not less or equal to b"
fi

Shell字符串

  • 单引号(原样输出)
  • 双引号(可以转义、变量等)
  • 拼接字符串
  • 获取字符串长度
  • 提取字符串
  • 查找字符串

Shell数组:shell数组的定义、数组长度

  • 定义数组
  • 读取数组
  • 获取数组的长度

Shell echo命令

shell printf命令:格式化输出语句

Shell if else语句

if 语句通过关系运算符判断表达式的真假来决定执行哪个分支。Shell 有三种 if … else 语句:

  • if … fi 语句;
  • if … else … fi 语句;
  • if … elif … else … fi 语句。

Shell case esac语句

类似于其他语言的switch...case语句。

Shell for循环

与其他编程语言类似,Shell支持for循环。

for循环一般格式为:

for 变量 in 列表
do
    command1
    command2
    ...
    commandN
done

列表是一组值(数字、字符串等)组成的序列,每个值通过空格分隔。每循环一次,就将列表中的下一个值赋给变量。

in 列表是可选的,如果不用它,for 循环使用命令行的位置参数。

例如,顺序输出当前列表中的数字:

for loop in 1 2 3 4 5
do
    echo "The value is: $loop"
done

运行结果:

The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5

显示主目录下以 .bash 开头的文件:

#!/bin/bash
for FILE in $HOME/.bash*
do
   echo $FILE
done

运行结果:

/root/.bash_history
/root/.bash_logout
/root/.bash_profile
/root/.bashrc

Shell while循环

while command
#该语言使用do和done来进行控制循环代码块
do 
   Statement(s) to be executed if command is true
done

Shell until循环

until 循环执行一系列命令直至条件为 true 时停止。until 循环与 while 循环在处理方式上刚好相反。一般while循环优于until循环,但在某些时候,也只是极少数情况下,until 循环更加有用。

until 循环格式为:

until command
do
   Statement(s) to be executed until command is true
done

command 一般为条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环。

例如,使用 until 命令输出 0 ~ 9 的数字:

#!/bin/bash
a=0
until [ ! $a -lt 10 ]
do
   echo $a
   a=`expr $a + 1`
done

运行结果:

0
1
2
3
4
5
6
7
8
9

## Shell break和continue命令

## Shell函数:Shell函数返回值、删除函数、在终端调用函数

函数可以让我们将一个复杂功能划分成若干模块,让程序结构更加清晰,代码重复利用率更高。像其他编程语言一样,Shell 也支持函数。Shell 函数必须先定义后使用。

Shell 函数的定义格式如下:

function_name () {
    list of commands
    [ return value ]
}

如果你愿意,也可以在函数名前加上关键字 function:

function function_name () {
    list of commands
    [ return value ]
}

函数返回值,可以显式增加return语句;如果不加,会将最后一条命令运行结果作为返回值。

Shell 函数返回值只能是整数,一般用来表示函数执行成功与否,0表示成功,其他值表示失败。如果 return 其他数据,比如一个字符串,往往会得到错误提示:“numeric argument required”。

如果一定要让函数返回字符串,那么可以先定义一个变量,用来接收函数的计算结果,脚本在需要的时候访问这个变量来获得函数返回值。

先来看一个例子:

#!/bin/bash
# Define your function here
Hello () {
   echo "Url is http://see.xidian.edu.cn/cpp/shell/"
}
# Invoke your function
Hello

运行结果:

$./test.sh
Hello World
$

调用函数只需要给出函数名,不需要加括号。

再来看一个带有return语句的函数:

#!/bin/bash
funWithReturn(){
    echo "The function is to get the sum of two numbers..."
    echo -n "Input first number: "
    read aNum
    echo -n "Input another number: "
    read anotherNum
    echo "The two numbers are $aNum and $anotherNum !"
    return $(($aNum+$anotherNum))
}
funWithReturn
# Capture value returnd by last command
ret=$?
echo "The sum of two numbers is $ret !"

运行结果:

The function is to get the sum of two numbers...
Input first number: 25
Input another number: 50
The two numbers are 25 and 50 !
The sum of two numbers is 75 !

函数返回值在调用该函数后通过 $? 来获得。

再来看一个函数嵌套的例子:

#!/bin/bash

# Calling one function from another
number_one () {
   echo "Url_1 is http://see.xidian.edu.cn/cpp/shell/"
   number_two
}

number_two () {
   echo "Url_2 is http://see.xidian.edu.cn/cpp/u/xitong/"
}

number_one

运行结果:

Url_1 is http://see.xidian.edu.cn/cpp/shell/
Url_2 is http://see.xidian.edu.cn/cpp/u/xitong/

像删除变量一样,删除函数也可以使用 unset 命令,不过要加上 .f 选项,如下所示:
$unset .f function_name
如果你希望直接从终端调用函数,可以将函数定义在主目录下的 .profile 文件,这样每次登录后,在命令提示符后面输入函数名字就可以立即调用。

Shell输入输出重定向:Shell Here Document,/dev/null文件

Shell文件包含

像其他语言一样,Shell 也可以包含外部脚本,将外部脚本的内容合并到当前脚本。

Shell 中包含脚本可以使用:

. filename

或

source filename

两种方式的效果相同,简单起见,一般使用点号(.),但是注意点号(.)和文件名中间有一空格。

例如,创建两个脚本,一个是被调用脚本 subscript.sh,内容如下:

url="http://see.xidian.edu.cn/cpp/view/2738.html"

一个是主文件 main.sh,内容如下:

#!/bin/bash
. ./subscript.sh
echo $url

执行脚本:

$chomd +x main.sh
./main.sh
http://see.xidian.edu.cn/cpp/view/2738.html
$

注意:被包含脚本不需要有执行权限。

Linux基本入门

发表于 2015-04-07   |   分类于 Linux基础   |     |   阅读次数

选择一个Linux的发行版本

学习Linux的第一件事情,就是要选择一个Linux的发行版本,在虚拟机或者物理机安装都可以了,初学者最好用虚拟机。初学Linux的第一件事情,就是看到众多的Linux分支而头晕,这到底有什么区别呢,为啥Linux不是只有一个版本,而是有很多个版本呢?其实是这样的,Linux其实是一个操作系统内核,但是一个操作系统除了内核,还有用户操作界面,应用软件,例如我们使用的windows,也有windows内核,出了windows内核,还有windows的图形界面,windows的office等应用软件。而Linux是一个免费开源的内核,每个厂家都可以去Linux内核官网http://www.kernel.org/下载内核,然后去订制自己的图形界面和应用软件,所以会出现很多Linux分支,但是内核都是一样的。

目前Linux只要有几个分支:redhat,ubuntu,debian,suse。很多其他linux发行版本是这几个分支的衍生版本,例如国内的红旗,centos都是redhat的衍生版本。

在服务器领域,个人觉得redhat现在做的最好,桌面领域是ubuntu最好,而我们学习Linux的最大目的是学习Linux的服务器领域,所以我推荐redhat版本。

学校里的linux课本都比较陈旧,大部分是Redhat Linux 9的教程,但是Redhat Linux 9由于硬盘驱动关系,是无法在现在的物理机上安装的,包括本人,也受过大学课本的误导(坑爹的教科书)。

Redhat Linux 9之后,redhat公司不在维护Redhat的开源版本,于是直接发行他的商业版本Redhat Enterprise Linux 2,目前已经有Redhat Enterprise Linux 6,但是6的稳定性还不清楚,个人推荐使用Redhat Enterprise Linux 5,请自行去网上下载Redhat Enterprise Linux 5。

Redhat Enterprise Linux虽然说是商业版本,但是只要你安装的时候,确定你不输入序列号,你还是可以正常使用,只是不能在redhat官网更新软件而已,然后,这里就要提下CentOS了,由于Redhat Enterprise Linux是商业版本,于是CentOS这个组织就和redhat公司买了源代码,并重新编译,免费开放出来,免费让用户可以在centos官网更新软件,包括使用Redhat Enterprise Linux的系统也可以在centos的官网更新软件。大家也可能有疑问,既然centos和redhat都是一模一样,除了名字不一样,为啥不选择centos。其实没任何区别,Centos 5.5就和Redhat Enterprise Linux 5.5是一模一样的,你可以选择centos去安装,去拿redhat的教程学习。

linux常用命令

  • 超级权限:sudo
  • 拷贝 cp N.java /home/M.java
  • 删除 rm [-rf] file.file
  • 关机 shutdown now
  • 挂载磁盘 mount 设备 挂载位置
  • Yum-yum [-y] install yum makecache 等

  • cat tac

  • vi file.file

Linux设置网络

。。。

Linux 设置权限

chmod u+x filename

Linux解压文件

tar xvf filename

Vim常见命令

vi两种模式,按i进入insert模式,按Esc返回到普通模式。

  • hjkl 左上下右
  • :wq[!] 保存并退出(quit)
1…456
Coder_Roc

Coder_Roc

关注技术趋势,服务端技术细节,Java语言,技术热点等,关注思维和最佳实践。

58 日志
10 分类
80 标签
RSS
GitHub Weibo Zhihu
© 2014 - 2017 Coder_Roc
由 Hexo 强力驱动
主题 - NexT.Pisces