2009年12月4日星期五

VirtualBox NAT设置和端口转发

这是我对 VirtualBox 自带帮助关于 NAT 设置部分的翻译,翻的不当处,请批评指正,我不是英语专业。未完,待续。转载我的文章,请注明出处,非常感谢。

1、 Network Address Translation (NAT)

Network Address Translation (NAT) is the simplest way of accessing an external network from a virtual machine. Usually, it does not require any configuration on the host network and guest system. For this reason, it is the default networking mode in VirtualBox.

网络地址转换( NAT )是最简单的方法从一个虚拟机访问外部网。通常,它并不要求在主机网络和客户机上做任何配置。基于这个原因,它是默认的网络模式 。

A virtual machine with NAT enabled acts much like a real computer that connects to the Internet through a router. The “router”, in this case, is the VirtualBox networking engine, which maps traffic from and to the virtual machine transparently. The disadvantage of NAT mode is that, much like a private network behind a router, the virtual machine is invisible and unreachable from the outside internet; you cannot run a server this way unless you set up port forwarding (described below).

设置为通过 NAT 方式连接的一台虚拟机能像一台真正的计算机一样访问互联网,主机就是一只路由器。 在这种方式下,通过 VirtualBox 网络引擎,虚拟机透明地映射到外部网络。 NAT 方式不方便是,很像是在路由器之后的一个专用网络,从外部互联网看来,虚拟机是无形和不能到达的; 您不可能在虚拟机上运行一个服务器,因为外部网络无法访问通过 NAT 方式连接的内部机,除非您设定了端口转发(下述)。

The virtual machine receives its network address and configuration on the private network from a DHCP server that is integrated into VirtualBox. The address which the virtual machine receives is usually on a completely different network to the host.As more than one card of a virtual machine can be set up to use NAT, the first card is connected to the private network 10.0.2.0, the second card to the network 10.0.3.0 and so on.

虚拟机从一个 VirtualBox 整合的 DHCP 服务器得到私有的网址。这个网址对主机来说是一个完全不同的网络。一台虚拟机的多个网卡可以被设定使用 NAT, 第一个网卡连接了到专用网 10.0.2.0,第二个网卡连接到专用网络 10.0.3.0,等等。默认得到的客户端ip(IP Address)是10.0.2.15,网关(Gateway)是10.0.2.2,域名服务器(DNS)是10.0.2.3,可以手动参考这个进行修改。

The network frames sent out by the guest operating system are received by VirtualBox’s NAT engine, which extracts the TCP/IP data, and resends it using the host operating system. To an application on the host, or to another computer on the same network as the host, it looks like the data was sent by the VirtualBox application on the host, using an IP address belonging to the host. VirtualBox listens for replies to the packages sent, and repacks and resends them to the guest machine on its private network.

客户机(即虚拟机)送出的网络帧被 VirtualBox 的 NAT 引擎收到,抽取 TCP/IP 数据,再通过主机的操作系统(即安装 VirtualBox 的操作系统)重新发送出去。送到在主机上的一个应用程序,或者到位于主机同一网络的另一台计算机上,它看起来好象是安装在主机上的程序 VirtualBox,通过一个属于主机的 IP 地址,把数据发送出去。VirtualBox 倾听到数据包裹的回复,通过客户机的私人网络重新包装和发送往客户机上。

You can set up a guest service which you wish to proxy using the command line tool VBoxManage. You will need to know which ports on the guest the service uses and to decide which ports to use on the host (often but not always you will want to se the same ports on the guest and on the host). You can use any ports on the host which are not already in use by a service. An example of how to set up incoming NAT connections to a ssh server on the guest requires the following three commands:

你可以设置一个虚拟机的服务(比如 WEB 服务),通过使用命令行工具 VboxManage 代理。你需要知道虚拟机的服务使用哪个端口,然后决定在主机上使用哪个端口(通常但不总是想要使虚拟机和主机使用同一个端口)。在主机上提供一个服务需要使用一个端口,你能使用在主机上没有准备用来提供服务的任何端口。一个怎样设置新的 NAT 例子,在虚拟机上连接到一个 ssh 服务器,需要下面的三个命令:

VBoxManage setextradata "Linux Guest" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/Protocol" TCP

VBoxManage setextradata "Linux Guest" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/GuestPort" 22

VBoxManage setextradata "Linux Guest" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/HostPort" 2222

说明:VboxManage 是一个命令行程序,请查询你的 VirtualBox 安装目录,"Linux Guest" 是虚拟主机名。guestssh 是一个自定义的名称,你可以任意设置,通过上面的三个命令,把虚拟机的 22 端口 转发到主机的 2222 端口。

又比如,我在虚拟机 debian 上安装了 apache2 服务器,使用 80 端口,映射到主机的 80 端口。使用下面的命令。

"C:\Program Files\innotek VirtualBox\VBoxManage.exe" setextradata "debian" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/huzhangsheng/Protocol" TCP

"C:\Program Files\innotek VirtualBox\VBoxManage.exe" setextradata "debian" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/huzhangsheng/GuestPort" 80

"C:\Program Files\innotek VirtualBox\VBoxManage.exe" setextradata "debian" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/huzhangsheng/HostPort" 80

注意:要使设置生效,请关掉 VirtualBox 再运行虚拟机,我把 VirtualBox 安装在 winxp 上,在虚拟机中安装 debian 4.02r ,虚拟机名是 debian ,并安装了 apache2 php5 mysql-server ,在主机上用IE浏览 http://localhost,成功转发到虚拟机 debian 的 apache2 web 服务器上,通过这点我发现:可能 VirtualBox 的设置比 vmware 更灵活,更强大。

2009年12月3日星期四

Linux 用户(user)和用户组(group)管理概述

摘要:本文主要讲述在Linux 系统中用户(user)和用户组(group)管理相应的概念;用户(user)和用户组(group)相关命令的列举;其中也对单用户多任务,多用户多任务也做以解说,本文应该说是比较基础的文档;

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
正文
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++

一、理解Linux的单用户多任务,多用户多任务概念;

Linux 是一个多用户、多任务的操作系统;我们应该了解单用户多任务和多用户多任务的概念;

1、Linux 的单用户多任务;

单用户多任务;比如我们以beinan 登录系统,进入系统后,我要打开gedit 来写文档,但在写文档的过程中,我感觉少点音乐,所以又打开xmms 来点音乐;当然听点音乐还不行,MSN 还得打开,想知道几个弟兄现在正在做什么,这样一样,我在用beinan 用户登录时,执行了gedit 、xmms以及msn等,当然还有输入法fcitx ;这样说来就有点简单了,一个beinan用户,为了完成工作,执行了几个任务;当然beinan这个用户,其它的人还能以远程登录过来,也能做其它的工作。

2、Linux 的多用户、多任务;

有时可能是很多用户同时用同一个系统,但并不所有的用户都一定都要做同一件事,所以这就有多用户多任务之说;

举个例子,比如LinuxSir.Org 服务器,上面有FTP 用户、系统管理员、web 用户、常规普通用户等,在同一时刻,可能有的弟兄正在访问论坛;有的可能在上传软件包管理子站,比如luma 或Yuking 兄在管理他们的主页系统和FTP ;在与此同时,可能还会有系统管理员在维护系统;浏览主页的用的是nobody 用户,大家都用同一个,而上传软件包用的是FTP用户;管理员的对系统的维护或查看,可能用的是普通帐号或超级权限root帐号;不同用户所具有的权限也不同,要完成不同的任务得需要不同的用户,也可以说不同的用户,可能完成的工作也不一样;

值得注意的是:多用户多任务并不是大家同时挤到一接在一台机器的的键盘和显示器前来操作机器,多用户可能通过远程登录来进行,比如对服务器的远程控制,只要有用户权限任何人都是可以上去操作或访问的;

3、用户的角色区分;

用户在系统中是分角色的,在Linux 系统中,由于角色不同,权限和所完成的任务也不同;值得注意的是用户的角色是通过UID和识别的,特别是UID;在系统管理中,系统管理员一定要坚守UID 唯一的特性;

root 用户:系统唯一,是真实的,可以登录系统,可以操作系统任何文件和命令,拥有最高权限;
虚拟用户:这类用户也被称之为伪用户或假用户,与真实用户区分开来,这类用户不具有登录系统的能力,但却是系统运行不可缺少的用户,比如bin、daemon、adm、ftp、mail等;这类用户都系统自身拥有的,而非后来添加的,当然我们也可以添加虚拟用户;
普通真实用户:这类用户能登录系统,但只能操作自己家目录的内容;权限有限;这类用户都是系统管理员自行添加的;

4、多用户操作系统的安全;

多用户系统从事实来说对系统管理更为方便。从安全角度来说,多用户管理的系统更为安全,比如beinan用户下的某个文件不想让其它用户看到,只是设置一下文件的权限,只有beinan一个用户可读可写可编辑就行了,这样一来只有beinan一个用户可以对其私有文件进行操作,Linux 在多用户下表现最佳,Linux能很好的保护每个用户的安全,但我们也得学会Linux 才是,再安全的系统,如果没有安全意识的管理员或管理技术,这样的系统也不是安全的。

从服务器角度来说,多用户的下的系统安全性也是最为重要的,我们常用的Windows 操作系统,它在系纺权限管理的能力只能说是一般般,根本没有没有办法和Linux或Unix 类系统相比;

二、用户(user)和用户组(group)概念;

1、用户(user)的概念;

通过前面对Linux 多用户的理解,我们明白Linux 是真正意义上的多用户操作系统,所以我们能在Linux系统中建若干用户(user)。比如我们的同事想用我的计算机,但我不想让他用我的用户名登录,因为我的用户名下有不想让别人看到的资料和信息(也就是隐私内容)这时我就可以给他建一个新的用户名,让他用我所开的用户名去折腾,这从计算机安全角度来说是符合操作规则的;

当然用户(user)的概念理解还不仅仅于此,在Linux系统中还有一些用户是用来完成特定任务的,比如nobody和ftp 等,我们访问LinuxSir.Org 的网页程序,就是nobody用户;我们匿名访问ftp 时,会用到用户ftp或nobody ;如果您想了解Linux系统的一些帐号,请查看 /etc/passwd ;

2、用户组(group)的概念;

用户组(group)就是具有相同特征的用户(user)的集合体;比如有时我们要让多个用户具有相同的权限,比如查看、修改某一文件或执行某个命令,这时我们需要用户组,我们把用户都定义到同一用户组,我们通过修改文件或目录的权限,让用户组具有一定的操作权限,这样用户组下的用户对该文件或目录都具有相同的权限,这是我们通过定义组和修改文件的权限来实现的;

举例:我们为了让一些用户有权限查看某一文档,比如是一个时间表,而编写时间表的人要具有读写执行的权限,我们想让一些用户知道这个时间表的内容,而不让他们修改,所以我们可以把这些用户都划到一个组,然后来修改这个文件的权限,让用户组可读,这样用户组下面的每个用户都是可读的;

用户和用户组的对应关系是:一对一、多对一、一对多或多对多;

一对一:某个用户可以是某个组的唯一成员;
多对一:多个用户可以是某个唯一的组的成员,不归属其它用户组;比如beinan和linuxsir两个用户只归属于beinan用户组;
一对多:某个用户可以是多个用户组的成员;比如beinan可以是root组成员,也可以是linuxsir用户组成员,还可以是adm用户组成员;
多对多:多个用户对应多个用户组,并且几个用户可以是归属相同的组;其实多对多的关系是前面三条的扩展;理解了上面的三条,这条也能理解;

三、用户(user)和用户组(group)相关的配置文件、命令或目录;

1、与用户(user)和用户组(group)相关的配置文件;

1)与用户(user)相关的配置文件;

/etc/passwd 注:用户(user)的配置文件;
/etc/shadow 注:用户(user)影子口令文件;

2)与用户组(group)相关的配置文件;

/etc/group 注:用户组(group)配置文件;
/etc/gshadow 注:用户组(group)的影子文件;

2、管理用户(user)和用户组(group)的相关工具或命令;

1)管理用户(user)的工具或命令;

useradd 注:添加用户
adduser 注:添加用户
passwd 注:为用户设置密码
usermod 注:修改用户命令,可以通过usermod 来修改登录名、用户的家目录等等;
pwcov 注:同步用户从/etc/passwd 到/etc/shadow
pwck 注:pwck是校验用户配置文件/etc/passwd 和/etc/shadow 文件内容是否合法或完整;
pwunconv 注:是pwcov 的立逆向操作,是从/etc/shadow和 /etc/passwd 创建/etc/passwd ,然后会删除 /etc/shadow 文件;
finger 注:查看用户信息工具
id 注:查看用户的UID、GID及所归属的用户组
chfn 注:更改用户信息工具
su 注:用户切换工具
sudo 注:sudo 是通过另一个用户来执行命令(execute a command as another user),su 是用来切换用户,然后通过切换到的用户来完成相应的任务,但sudo 能后面直接执行命令,比如sudo 不需要root 密码就可以执行root 赋与的执行只有root才能执行相应的命令;但得通过visudo 来编辑/etc/sudoers来实现;
visudo 注:visodo 是编辑 /etc/sudoers 的命令;也可以不用这个命令,直接用vi 来编辑 /etc/sudoers 的效果是一样的;
sudoedit 注:和sudo 功能差不多;

2)管理用户组(group)的工具或命令;

groupadd 注:添加用户组;
groupdel 注:删除用户组;
groupmod 注:修改用户组信息
groups 注:显示用户所属的用户组
grpck
grpconv 注:通过/etc/group和/etc/gshadow 的文件内容来同步或创建/etc/gshadow ,如果/etc/gshadow 不存在则创建;
grpunconv 注:通过/etc/group 和/etc/gshadow 文件内容来同步或创建/etc/group ,然后删除gshadow文件;

3、/etc/skel 目录;

/etc/skel目录一般是存放用户启动文件的目录,这个目录是由root权限控制,当我们添加用户时,这个目录下的文件自动复制到新添加的用户的家目录下;/etc/skel 目录下的文件都是隐藏文件,也就是类似.file格式的;我们可通过修改、添加、删除/etc/skel目录下的文件,来为用户提供一个统一、标准的、默认的用户环境;

[[email protected] beinan]# ls -la /etc/skel/
总用量 92
drwxr-xr-x 3 root root 4096 8月 11 23:32 .
drwxr-xr-x 115 root root 12288 10月 14 13:44 ..
-rw-r--r-- 1 root root 24 5月 11 00:15 .bash_logout
-rw-r--r-- 1 root root 191 5月 11 00:15 .bash_profile
-rw-r--r-- 1 root root 124 5月 11 00:15 .bashrc
-rw-r--r-- 1 root root 5619 2005-03-08 .canna
-rw-r--r-- 1 root root 438 5月 18 15:23 .emacs
-rw-r--r-- 1 root root 120 5月 23 05:18 .gtkrc
drwxr-xr-x 3 root root 4096 8月 11 23:16 .kde
-rw-r--r-- 1 root root 658 2005-01-17 .zshrc

/etc/skel 目录下的文件,一般是我们用useradd 和adduser 命令添加用户(user)时,系统自动复制到新添加用户(user)的家目录下;如果我们通过修改 /etc/passwd 来添加用户时,我们可以自己创建用户的家目录,然后把/etc/skel 下的文件复制到用户的家目录下,然后要用chown 来改变新用户家目录的属主;

4、/etc/login.defs 配置文件;

/etc/login.defs 文件是当创建用户时的一些规划,比如创建用户时,是否需要家目录,UID和GID的范围;用户的期限等等,这个文件是可以通过root来定义的;

比如Fedora 的 /etc/logins.defs 文件内容;

# *REQUIRED*
# Directory where mailboxes reside, _or_ name of file, relative to the
# home directory. If you _do_ define both, MAIL_DIR takes precedence.
# QMAIL_DIR is for Qmail
#
#QMAIL_DIR Maildir
MAIL_DIR /var/spool/mail 注:创建用户时,要在目录/var/spool/mail中创建一个用户mail文件;
#MAIL_FILE .mail

# Password aging controls:
#
# PASS_MAX_DAYS Maximum number of days a password may be used.
# PASS_MIN_DAYS Minimum number of days allowed between password changes.
# PASS_MIN_LEN Minimum acceptable password length.
# PASS_WARN_AGE Number of days warning given before a password expires.
#
PASS_MAX_DAYS 99999 注:用户的密码不过期最多的天数;
PASS_MIN_DAYS 0 注:密码修改之间最小的天数;
PASS_MIN_LEN 5 注:密码最小长度;
PASS_WARN_AGE 7 注:

#
# Min/max values for automatic uid selection in useradd
#
UID_MIN 500 注:最小UID为500 ,也就是说添加用户时,UID 是从500开始的;
UID_MAX 60000 注:最大UID为60000;

#
# Min/max values for automatic gid selection in groupadd
#
GID_MIN 500 注:GID 是从500开始;
GID_MAX 60000

#
# If defined, this command is run when removing a user.
# It should remove any at/cron/print jobs etc. owned by
# the user to be removed (passed as the first argument).
#
#USERDEL_CMD /usr/sbin/userdel_local

#
# If useradd should create home directories for users by default
# On RH systems, we do. This option is ORed with the -m flag on
# useradd command line.
#
CREATE_HOME yes 注:是否创用户家目录,要求创建;

5、/etc/default/useradd 文件;

通过useradd 添加用户时的规则文件;
# useradd defaults file
GROUP=100
HOME=/home 注:把用户的家目录建在/home中;
INACTIVE=-1 注:是否启用帐号过期停权,-1表示不启用;
EXPIRE= 注:帐号终止日期,不设置表示不启用;
SHELL=/bin/bash 注:所用SHELL的类型;
SKEL=/etc/skel 注: 默认添加用户的目录默认文件存放位置;也就是说,当我们用adduser添加用户时,用户家目录下的文件,都是从这个目录中复制过去的;

后记:

关于用户(user)和用户组(group)管理内容大约就是这么多;只要把上面所说的内容了解和掌握,用户(user)和用户组(group)管理就差不多了;由于用户(user)和用户组(group)是和文件及目录权限联系在一起的,所以文件及目录权限的操作也会独立成文来给大家介绍;

本文只是让新手弟兄明白用户(user)和用户组(group)一些原理,所以我在写此文的时候,大多是解说内容,我的意思是通过解说和索引一些命令,让新手弟兄明白一点理论是比较重要的,技术操作无非是命令的用法;

本文内容会不断的更新和变动,一些命令需要独立成文加以解说,我会在最近的几天内完成;

参考文档:

Linux 相关的man 和相关的help ;

致谢:

对于本文,pandonny 兄也有贡献,谢谢;

相关文档:

《Linux 用户(user)和用户组(group)管理概述》
《用户(user)和用户组(group)配置文件详解》
《Linux 用户(User)查询篇》
《Linux 用户管理工具介绍》
《Linux 系统中的超级权限的控制》
《在Linux系统中,批量添加用户的操作流程》

想改變logo範圍 的大小

從佈景主題 HTML 編輯器可看到 logo 部分的程式碼 /templates/ja_purity/index.php
<?php
$siteName = $tmpTools->sitename();
if ($tmpTools->getParam('logoType')=='image'): ?>
<h1>
<a href="index.php" title="<?php echo $siteName; ?>"><span><?php echo $siteName; ?></span></a>
</h1>

查一下 template.css
可看到
h1.logo a {
width: 208px;
display: block;
background: url(../images/logo.png) no-repeat;
height: 80px;
position: relative;
z-index: 100;
}

修改其中的 width, height 即可

PHPBB-分区和版面不显示的问题

装了个PHPBB3,在后台设置好分区后发现前台只显示了2个分区。
讶异的Google了下,似乎很少有人碰到这个问题……好奇怪…
于是怀疑是皮肤文件的限制,但是换了个皮肤还是这样子。
只好继续找,还真给找到了,原来是权限设置的问题!
PHPBB里边所有的分区跟板块都必须设置权限后才会在前台显示,
只设置分区权限或者只设置版面权限都是不行的,一定要都设置。
不知道怎么设置的话可以复制系统默认的那个分区。

改變您的論壇 logo

內容
• 開始
• 上傳您的 Logo
• 重新整理您的風格主題 (Theme)
• 重新調整您的 Logo 尺寸
• 結束 (完成)

開始
這篇文章旨在說明如何上傳一個新的 logo 到您的 phpBB3 論壇.

如果您之前沒有上傳檔案的經驗, 或者不知道如何使用 'FTP', 那麼請在繼續下文前, 先行研讀這篇教學.

上傳您的 Logo
哈! 您真的想要用您自己的 logo 取代 phpBB 的嗎?

首先, 您必須找到您自己 (創建) 的 logo, 以及將它 (重新) 命名為 'site_logo.gif'. 注意! 檔案名稱完全是小寫字體.

接著, 使用您的 FTP 用戶端軟體, 將它上傳到: phpBB3/styles/prosilver/imageset/ (*) 底下,
覆蓋現存的 logo.

您已經成功地上傳您的 logo.

(*) 假設您使用的是 prosilver 風格.

重新整理您的風格主題 (Theme)
因為您已經使用新的 logo 覆蓋現存的檔案系統, 所以必須要重新整理以顯示出您的改變.

登入您的論壇, 並且進入管理員控制台 (ACP).
從這裡, 點選 '風格' 標籤, 選擇 '主題', 再點選您所使用的風格之 '重新整理'.

您的新 logo 現在應該可以顯示在論壇上. 如果還不行, 那麼試試重新整理您的瀏覽器.

重新調整您的 Logo 尺寸
您的新 logo 是否破壞了版面 (歪了)? 這是因為您的新 logo 有不一樣尺寸.

回到 ACP -> 風格 -> 圖檔組.
再點選您所使用的風格之 '編輯'.
在下拉式選單中, 選擇 '主要的 logo', 以及按下 '選擇' 鈕.
在下方, 您將看見圖檔寬度以及高度的選項.
輸入正確的 logo 尺寸後, 按送出.

結束 (完成)
您現在應該都做完了.

如果這 logo 還是沒有正確地顯示, 那麼請再試著重新整理您的風格.

http://phpbb-tw.net/phpbb/viewtopic.php?f=176&t=51343

MySQL Commands

This is a list of handy MySQL commands that I use time and time again. At the bottom are statements, clauses, and functions you can use in MySQL. Below that are PHP and Perl API functions you can use to interface with MySQL. To use those you will need to build PHP with MySQL functionality. To use MySQL with Perl you will need to use the Perl modules DBI and DBD::mysql.

Below when you see # it means from the unix shell. When you see mysql> it means from a MySQL prompt after logging into MySQL.
To login (from unix shell) use -h only if needed.

# [mysql dir]/bin/mysql -h hostname -u root -p
Create a database on the sql server.

mysql> create database [databasename];
List all databases on the sql server.

mysql> show databases;
Switch to a database.

mysql> use [db name];
To see all the tables in the db.

mysql> show tables;
To see database's field formats.

mysql> describe [table name];
To delete a db.

mysql> drop database [database name];
To delete a table.

mysql> drop table [table name];
Show all data in a table.

mysql> SELECT * FROM [table name];
Returns the columns and column information pertaining to the designated table.

mysql> show columns from [table name];
Show certain selected rows with the value "whatever".

mysql> SELECT * FROM [table name] WHERE [field name] = "whatever";
Show all records containing the name "Bob" AND the phone number '3444444'.

mysql> SELECT * FROM [table name] WHERE name = "Bob" AND phone_number = '3444444';
Show all records not containing the name "Bob" AND the phone number '3444444' order by the phone_number field.

mysql> SELECT * FROM [table name] WHERE name != "Bob" AND phone_number = '3444444' order by phone_number;
Show all records starting with the letters 'bob' AND the phone number '3444444'.

mysql> SELECT * FROM [table name] WHERE name like "Bob%" AND phone_number = '3444444';
Show all records starting with the letters 'bob' AND the phone number '3444444' limit to records 1 through 5.

mysql> SELECT * FROM [table name] WHERE name like "Bob%" AND phone_number = '3444444' limit 1,5;
Use a regular expression to find records. Use "REGEXP BINARY" to force case-sensitivity. This finds any record beginning with a.

mysql> SELECT * FROM [table name] WHERE rec RLIKE "^a";
Show unique records.

mysql> SELECT DISTINCT [column name] FROM [table name];
Show selected records sorted in an ascending (asc) or descending (desc).

mysql> SELECT [col1],[col2] FROM [table name] ORDER BY [col2] DESC;
Return number of rows.

mysql> SELECT COUNT(*) FROM [table name];
Sum column.

mysql> SELECT SUM(*) FROM [table name];
Join tables on common columns.

mysql> select lookup.illustrationid, lookup.personid,person.birthday from lookup left join person on lookup.personid=person.personid=statement to join birthday in person table with primary illustration id;
Creating a new user. Login as root. Switch to the MySQL db. Make the user. Update privs.

# mysql -u root -p
mysql> use mysql;
mysql> INSERT INTO user (Host,User,Password) VALUES('%','username',PASSWORD('password'));
mysql> flush privileges;
Change a users password from unix shell.

# [mysql dir]/bin/mysqladmin -u username -h hostname.blah.org -p password 'new-password'
Change a users password from MySQL prompt. Login as root. Set the password. Update privs.

# mysql -u root -p
mysql> SET PASSWORD FOR 'user'@'hostname' = PASSWORD('passwordhere');
mysql> flush privileges;
Recover a MySQL root password. Stop the MySQL server process. Start again with no grant tables. Login to MySQL as root. Set new password. Exit MySQL and restart MySQL server.

# /etc/init.d/mysql stop
# mysqld_safe --skip-grant-tables &
# mysql -u root
mysql> use mysql;
mysql> update user set password=PASSWORD("newrootpassword") where User='root';
mysql> flush privileges;
mysql> quit
# /etc/init.d/mysql stop
# /etc/init.d/mysql start
Set a root password if there is on root password.

# mysqladmin -u root password newpassword
Update a root password.

# mysqladmin -u root -p oldpassword newpassword
Allow the user "bob" to connect to the server from localhost using the password "passwd". Login as root. Switch to the MySQL db. Give privs. Update privs.

# mysql -u root -p
mysql> use mysql;
mysql> grant usage on *.* to [email protected] identified by 'passwd';
mysql> flush privileges;
Give user privilages for a db. Login as root. Switch to the MySQL db. Grant privs. Update privs.

# mysql -u root -p
mysql> use mysql;
mysql> INSERT INTO user (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv) VALUES ('%','databasename','username','Y','Y','Y','Y','Y','N');
mysql> flush privileges;

or

mysql> grant all privileges on databasename.* to [email protected];
mysql> flush privileges;
To update info already in a table.

mysql> UPDATE [table name] SET Select_priv = 'Y',Insert_priv = 'Y',Update_priv = 'Y' where [field name] = 'user';
Delete a row(s) from a table.

mysql> DELETE from [table name] where [field name] = 'whatever';
Update database permissions/privilages.

mysql> flush privileges;
Delete a column.

mysql> alter table [table name] drop column [column name];
Add a new column to db.

mysql> alter table [table name] add column [new column name] varchar (20);
Change column name.

mysql> alter table [table name] change [old column name] [new column name] varchar (50);
Make a unique column so you get no dupes.

mysql> alter table [table name] add unique ([column name]);
Make a column bigger.

mysql> alter table [table name] modify [column name] VARCHAR(3);
Delete unique from table.

mysql> alter table [table name] drop index [colmn name];
Load a CSV file into a table.

mysql> LOAD DATA INFILE '/tmp/filename.csv' replace INTO TABLE [table name] FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' (field1,field2,field3);
Dump all databases for backup. Backup file is sql commands to recreate all db's.

# [mysql dir]/bin/mysqldump -u root -ppassword --opt >/tmp/alldatabases.sql
Dump one database for backup.

# [mysql dir]/bin/mysqldump -u username -ppassword --databases databasename >/tmp/databasename.sql
Dump a table from a database.

# [mysql dir]/bin/mysqldump -c -u username -ppassword databasename tablename > /tmp/databasename.tablename.sql
Restore database (or database table) from backup.

# [mysql dir]/bin/mysql -u username -ppassword databasename < /tmp/databasename.sql
Create Table Example 1.

mysql> CREATE TABLE [table name] (firstname VARCHAR(20), middleinitial VARCHAR(3), lastname VARCHAR(35),suffix VARCHAR(3),officeid VARCHAR(10),userid VARCHAR(15),username VARCHAR(8),email VARCHAR(35),phone VARCHAR(25), groups VARCHAR(15),datestamp DATE,timestamp time,pgpemail VARCHAR(255));
Create Table Example 2.

mysql> create table [table name] (personid int(50) not null auto_increment primary key,firstname varchar(35),middlename varchar(50),lastnamevarchar(50) default 'bato');

MYSQL Statements and clauses

ALTER DATABASE

ALTER TABLE

ALTER VIEW

ANALYZE TABLE

BACKUP TABLE

CACHE INDEX

CHANGE MASTER TO

CHECK TABLE

CHECKSUM TABLE

COMMIT

CREATE DATABASE

CREATE INDEX

CREATE TABLE

CREATE VIEW

DELETE

DESCRIBE

DO

DROP DATABASE

DROP INDEX

DROP TABLE

DROP USER

DROP VIEW

EXPLAIN

FLUSH

GRANT

HANDLER

INSERT

JOIN

KILL

LOAD DATA FROM MASTER

LOAD DATA INFILE

LOAD INDEX INTO CACHE

LOAD TABLE...FROM MASTER

LOCK TABLES

OPTIMIZE TABLE

PURGE MASTER LOGS

RENAME TABLE

REPAIR TABLE

REPLACE

RESET

RESET MASTER

RESET SLAVE

RESTORE TABLE

REVOKE

ROLLBACK

ROLLBACK TO SAVEPOINT

SAVEPOINT

SELECT

SET

SET PASSWORD

SET SQL_LOG_BIN

SET TRANSACTION

SHOW BINLOG EVENTS

SHOW CHARACTER SET

SHOW COLLATION

SHOW COLUMNS

SHOW CREATE DATABASE

SHOW CREATE TABLE

SHOW CREATE VIEW

SHOW DATABASES

SHOW ENGINES

SHOW ERRORS

SHOW GRANTS

SHOW INDEX

SHOW INNODB STATUS

SHOW LOGS

SHOW MASTER LOGS

SHOW MASTER STATUS

SHOW PRIVILEGES

SHOW PROCESSLIST

SHOW SLAVE HOSTS

SHOW SLAVE STATUS

SHOW STATUS

SHOW TABLE STATUS

SHOW TABLES

SHOW VARIABLES

SHOW WARNINGS

START SLAVE

START TRANSACTION

STOP SLAVE

TRUNCATE TABLE

UNION

UNLOCK TABLES

USE

String Functions

AES_DECRYPT

AES_ENCRYPT

ASCII

BIN

BINARY

BIT_LENGTH

CHAR

CHAR_LENGTH

CHARACTER_LENGTH

COMPRESS

CONCAT

CONCAT_WS

CONV

DECODE

DES_DECRYPT

DES_ENCRYPT

ELT

ENCODE

ENCRYPT

EXPORT_SET

FIELD

FIND_IN_SET

HEX

INET_ATON

INET_NTOA

INSERT

INSTR

LCASE

LEFT

LENGTH

LOAD_FILE

LOCATE

LOWER

LPAD

LTRIM

MAKE_SET

MATCH AGAINST

MD5

MID

OCT

OCTET_LENGTH

OLD_PASSWORD

ORD

PASSWORD

POSITION

QUOTE

REPEAT

REPLACE

REVERSE

RIGHT

RPAD

RTRIM

SHA

SHA1

SOUNDEX

SPACE

STRCMP

SUBSTRING

SUBSTRING_INDEX

TRIM

UCASE

UNCOMPRESS

UNCOMPRESSED_LENGTH

UNHEX

UPPER

Date and Time Functions

ADDDATE

ADDTIME

CONVERT_TZ

CURDATE

CURRENT_DATE

CURRENT_TIME

CURRENT_TIMESTAMP

CURTIME

DATE

DATE_ADD

DATE_FORMAT

DATE_SUB

DATEDIFF

DAY

DAYNAME

DAYOFMONTH

DAYOFWEEK

DAYOFYEAR

EXTRACT

FROM_DAYS

FROM_UNIXTIME

GET_FORMAT

HOUR

LAST_DAY

LOCALTIME

LOCALTIMESTAMP

MAKEDATE

MAKETIME

MICROSECOND

MINUTE

MONTH

MONTHNAME

NOW

PERIOD_ADD

PERIOD_DIFF

QUARTER

SEC_TO_TIME

SECOND

STR_TO_DATE

SUBDATE

SUBTIME

SYSDATE

TIME

TIMEDIFF

TIMESTAMP

TIMESTAMPDIFF

TIMESTAMPADD

TIME_FORMAT

TIME_TO_SEC

TO_DAYS

UNIX_TIMESTAMP

UTC_DATE

UTC_TIME

UTC_TIMESTAMP

WEEK

WEEKDAY

WEEKOFYEAR

YEAR

YEARWEEK

Mathematical and Aggregate Functions

ABS

ACOS

ASIN

ATAN

ATAN2

AVG

BIT_AND

BIT_OR

BIT_XOR

CEIL

CEILING

COS

COT

COUNT

CRC32

DEGREES

EXP

FLOOR

FORMAT

GREATEST

GROUP_CONCAT

LEAST

LN

LOG

LOG2

LOG10

MAX

MIN

MOD

PI

POW

POWER

RADIANS

RAND

ROUND

SIGN

SIN

SQRT

STD

STDDEV

SUM

TAN

TRUNCATE

VARIANCE

Flow Control Functions

CASE

IF

IFNULL

NULLIF

Command-Line Utilities

comp_err

isamchk

make_binary_distribution

msql2mysql

my_print_defaults

myisamchk

myisamlog

myisampack

mysqlaccess

mysqladmin

mysqlbinlog

mysqlbug

mysqlcheck

mysqldump

mysqldumpslow

mysqlhotcopy

mysqlimport

mysqlshow

perror

Perl API - using functions and methods built into the Perl DBI with MySQL

available_drivers

begin_work

bind_col

bind_columns

bind_param

bind_param_array

bind_param_inout

can

clone

column_info

commit

connect

connect_cached

data_sources

disconnect

do

dump_results

err

errstr

execute

execute_array

execute_for_fetch

fetch

fetchall_arrayref

fetchall_hashref

fetchrow_array

fetchrow_arrayref

fetchrow_hashref

finish

foreign_key_info

func

get_info

installed_versions

last_insert_id

looks_like_number

neat

neat_list

parse_dsn

parse_trace_flag

parse_trace_flags

ping

prepare

prepare_cached

primary_key

primary_key_info

quote

quote_identifier

rollback

rows

selectall_arrayref

selectall_hashref

selectcol_arrayref

selectrow_array

selectrow_arrayref

selectrow_hashref

set_err

state

table_info

table_info_all

tables

trace

trace_msg

type_info

type_info_all

Attributes for Handles

PHP API - using functions built into PHP with MySQL

mysql_affected_rows

mysql_change_user

mysql_client_encoding

mysql_close

mysql_connect

mysql_create_db

mysql_data_seek

mysql_db_name

mysql_db_query

mysql_drop_db

mysql_errno

mysql_error

mysql_escape_string

mysql_fetch_array

mysql_fetch_assoc

mysql_fetch_field

mysql_fetch_lengths

mysql_fetch_object

mysql_fetch_row

mysql_field_flags

mysql_field_len

mysql_field_name

mysql_field_seek

mysql_field_table

mysql_field_type

mysql_free_result

mysql_get_client_info

mysql_get_host_info

mysql_get_proto_info

mysql_get_server_info

mysql_info

mysql_insert_id

mysql_list_dbs

mysql_list_fields

mysql_list_processes

mysql_list_tables

mysql_num_fields

mysql_num_rows

mysql_pconnect

mysql_ping

mysql_query

mysql_real_escape_string

mysql_result

mysql_select_db

mysql_stat

mysql_tablename

mysql_thread_id

mysql_unbuffered_query

http://www.pantz.org/software/mysql/mysqlcommands.html

百度面试题--linux[转]

这篇文章是转载的哦,大家都误会了~我不是东软的
=========================================

1.假设Apache产生的日志文件名为access_log,在apache正在运行时,执行命令mv
access_log access_log.bak,执行完后,请问新的apache的日志会打印到哪里,为什么?
1、新的日志会打印在access_log.bak中,因为apache启动时会找到access_log文件,随时准备向文件中加入日志信息,
虽然此时文件被改名,但是由于服务正在运行,因为它的inode节点的位置没有变,程序打开的fd仍然会指向原来那个inode,
不会因为文件名的改变而改变。apache会继续向已改名的文件中追加日志,但是若重启apache服务,系统会检查access_log
文件是否存在,若不存在则创建。
2.在Shell环境下,如何查看远程Linux系统运行了多少时间?
2、监控主机执行: ssh [email protected]被监控主机ip "uptime"
这样得到了被监控主机的uptime
3.处理以下文件内容,将域名取出并进行计数排序,如处理:
http://www.baidu.com/index.html
http://www.baidu.com/1.html
http://post.baidu.com/index.html
http://mp3.baidu.com/index.html
http://www.baidu.com/3.html
http://post.baidu.com/2.html
得到如下结果:
域名的出现的次数 域名
3 www.baidu.com
2 post.baidu.com
1 mp3.baidu.com
可以使用bash/perl/php/c任意一种
3、[[email protected] shell]# cat file | sed -e ' s/http:\/\///' -e ' s/\/.*//' | sort | uniq -c | sort -rn
3 www.baidu.com
2 post.baidu.com
1 mp3.baidu.com
[[email protected] shell]# awk -F/ '{print $3}' file |sort -r|uniq -c|awk '{print $1"\t",$2}'
3 www.baidu.com
2 post.baidu.com
1 mp3.baidu.com

4.如果得到随机的字串,长度和字串中出现的字符表可定义,并将字串倒序显示,如
把0123456789作为基准的字串字符表,产生一个6位的字串642031,打印出的字串为
130246,可使用bash/perl/php/c任意一种.
4、[[email protected] ~]# awk -v count=6 'BEGIN {srand();str="0123456789";len=length(str);for(i=count;i>0;i--) marry[i]=substr(str,int(rand()*len),1);for(i=count;i>0;i--) printf("%c",marry[i]);printf("\n");for

(i=0;i<=count;i++) printf("%c",marry[i]);printf("\n")}'
838705
507838
5.如何查看当前Linux系统的状态,如CPU使用,内存使用,负载情况等.
5、Linux系统中“/proc”是个伪文件目录,不占用系统空间,及时的反应出内存现在使用的进程情况......其中许多文件都保存系统运行状态和相关信息
对于“/proc”中文件可使用文件查看命令浏览其内容,文件中包含系统特定信息:
cpuinfo 主机CPU信息
filesystems 文件系统信息
meninfo 主机内存信息
version Linux内存版本信息
diskstatus 磁盘负载情况
另外top命令可以动态的显示当前系统进程用户的使用情况,而且是动态的显示出来,尤其是在该命令显示出来的对上方对系统的情况进行汇总.
free命令呢可以查看真实使用的内存 一般用free -m
使用lsof 、ps -aux 可以查看详细的每个进程的使用状况
dmesg 也是常用来查看系统性能的命令
#######################################################################################################################################################################
#题目:有10台被监控主机、一台监控机,在监控机上编写脚本,一旦某台被监控机器/分区适用率大于80%, 就发邮件报警放到crontab里面, 每10分钟检查一次
#测试机器:虚拟机Linux as 4
#1.首先建立服务器间的信任关系。拿两台机器做测试
本机ip:192.168.1.6
[[email protected] ~]# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
/root/.ssh/id_rsa already exists.
Overwrite (y/n)? y (以为我是第2次建立关系所以此处覆盖原来的文件)
Enter passphrase (empty for no passphrase):(直接回车无须输入密钥)
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
04:37:13:2a:4b:10:af:c1:2b:03:3f:6b:27:ce:b9:62 [email protected]
[[email protected] ~]# cd .ssh/
[[email protected] .ssh]# ll
-rw------- 1 root root 883 Apr 25 17:51 id_rsa
-rw-r--r-- 1 root root 221 Apr 25 17:51 id_rsa.pub
-rw-r--r-- 1 root root 442 Apr 25 17:37 known_hosts
id_rsa是密钥文件,id_rsa.pub是公钥文件。
[[email protected] .ssh]# scp id_rsa.pub192.168.1.4:/root/.ssh/192.168.1.6
[email protected]'s password:
id_rsa.pub 100% 221 0.2KB/s 00:00
这里把公钥文件取名为本机的ip地址就是为了以后和更多的机器建立信任关系不发生混淆。
现在登陆到192.168.1.4机器
[[email protected] ~]# cd .ssh/
[[email protected] .ssh]# cat 192.168.1.6 >> authorized_keys
然后回到192.168.1.6机器直接
[[email protected] .ssh]# ssh 192.168.1.4
Last login: Wed Aug 8 12:14:42 2007 from 192.168.1.6
这样就可以了,里面偶尔涉及到权限问题。一般./ssh文件夹是755 authorized_keys为600或者644

####脚本如下#######################

#!/bin/bash
#SCRIPT:df_check.sh
#Writeen by codfei Mon Sep 3 07:25:28 CST 2007
#PURPOSE:This script is used to monitor for full filesystems.
#######################Begining########################################
FSMAX="80"
remote_user='root' #####完全可以不用root
remote_ip=(192.168.1.5 192.168.1.6 192.168.1.7 192.168.1.8 192.168.1.9 192.168.1.10 192.168.1.11 192.168.1.12 192.168.1.13 192.168.1.14 )
###这里填写你要监控的主机ip
ip_num='0'
while [ "$ip_num" -le "$(expr ${#remote_ip[@]} - 1)" ]
do
read_num='1'
ssh "$remote_user"@"${remote_ip[$ip_num]}" df -h > /tmp/diskcheck_tmp
grep '^/dev/*' /tmp/diskcheck_tmp|awk '{print $5}'|sed 's/\%//g' > /tmp/diskcheck_num_tmp
while [ "$read_num" -le $(wc -l < /tmp/diskcheck_num_tmp) ]
do
size=$(sed -n "$read_num"'p' /tmp/diskcheck_num_tmp)
if [ "$size" -gt "$FSMAX" ]
then
$(grep '^/dev/*' /tmp/diskcheck_tmp|sed -n $read_num'p' > /tmp/disk_check_mail)
$(echo ${remote_ip[$ip_num]} >> /tmp/disk_check_mail)
$(mail -s "diskcheck_alert" admin < /tmp/disk_check_mail)
fi
read_num=$(expr $read_num + 1)
done
ip_num=$(expr $ip_num + 1)
done

#############over################################
################让脚本每十分钟执行一次#############
在cron表中加入
0/10 * * * * /home/codfei/diskcheck.sh 2>&1

##########################################################################
比如, ext2文件系统, 如果异常死机,开机如何修复文件系统?
如果异常关机,比如断电,通知机房的人开机之后,
我们需要远程修复、检查文件系统
除了/分区之外, 其他的分区:
umount /home
fsck -y /home
/ 分区需要开机之后, 由机房的人来扫描
随后我们再登录并扫描/home等其他分区
如何查看一个进程所使用的文件句柄?
看这里面 /proc/进程号/fd/
的个数就行了
简单的比如如何查看apache进程数
[[email protected] fd]# ps -ef|grep httpd|wc -l
1
如何统计apache的每秒访问数?
tail access_log | awk '{print $1,$4}'
[[email protected] logs]# grep -c `date -d '3 second ago' +%T` access_log
0
#######################################################################################################################
#######################################################################################################################
1、/proc/sys 子目录的作用
该子目录的作用是报告各种不同的内核参数,并让您能交互地更改其中的某些。与 /proc 中所有其他文件不同,该目录中的某些文件可以写入,不过这仅针对 root。

其中的目录以及文件的详细列表将占据过多的篇幅,而且该目录的内容是依赖于系统的,而大部分的文件也仅仅对某些特殊的应用程序有用。然而,以下是该子目录的两个最常见的用途:

允许路由:即便是 Mandrakelinux 默认的内核也是允许路由的,您必需显式允许它这么做。为此,您只要以 root 身份键入以下命令:

$ echo 1 >/proc/sys/net/ipv4/ip_forward

如果您要禁用路由,请将上述命令中的 1 改为 0。

阻止 IP 欺骗:IP 欺骗会让人认为某个来自于外部的某个数据包是来自于它到达的那个接口。这一技术常被骇客(cracker)所使用。您可以让内核阻止这种入侵。请键入:

$ echo 1 >/proc/sys/net/ipv4/conf/all/rp_filter

这样,这种攻击就不再可能了。

这些改变仅当系统运行时有效。在系统重新启动之后,它们会改会它们的默认值。要在启动时就改动这些值,您可以将您在 shell 提示符后键入的命令添加到 /etc/rc.d/rc.local 中以免每次都键入它们。另一个方法是修改

/etc/sysctl.conf
2、将一个文本的奇数行和偶数行合并,第2行和第3行合并
[[email protected] bin]# cat 1
48 Oct 3bc1997 lpas 68.00 lvx2a 138
484 Jan 380sdf1 usp 78.00 deiv 344
483 nov 7pl1998 usp 37.00 kvm9d 644
320 aug der9393 psh 83.00 wiel 293
231 jul sdf9dsf sdfs 99.00 werl 223
230 nov 19dfd9d abd 87.00 sdiv 230
219 sept 5ap1996 usp 65.00 lvx2c 189
216 Sept 3zl1998 usp 86.00 kvm9e 234
[[email protected] bin]# sed '$!N;s/\n/ /g' 1
48 Oct 3bc1997 lpas 68.00 lvx2a 138 484 Jan 380sdf1 usp 78.00 deiv 344
483 nov 7pl1998 usp 37.00 kvm9d 644 320 aug der9393 psh 83.00 wiel 293
231 jul sdf9dsf sdfs 99.00 werl 223 230 nov 19dfd9d abd 87.00 sdiv 230
219 sept 5ap1996 usp 65.00 lvx2c 189 216 Sept 3zl1998 usp 86.00 kvm9e 234
[[email protected] bin]# sed -n -e 2p -e 3p 1|sed '$!N;s/\n/ /'
484 Jan 380sdf1 usp 78.00 deiv 344 483 nov 7pl1998 usp 37.00 kvm9d 644
3、read 命令5秒后自动退出
[[email protected] bin]# read -t 5
4、自动ftp上传
#!/bin/sh
ftp -n<<END_FTP
open 192.168.1.4
user codfei duibuqi //用户名codfei 密码duibuqi
binary
prompt off //关闭提示
mput test //上传test
close
bye
END_FTP
自动ssh登陆 从A到B然后再到c
#!/usr/bin/expect -f
set timeout 30
spawn ssh [email protected]
expect "password:"
send "pppppp\r"
expect "]*"
send "ssh [email protected]\r"
expect "password:"
send "pppppp\r"
interact

5、#打印第一个域
[[email protected] bin]# cat 3
eqeqedadasdD
eqeqdadfdfDD
fdsfdsfQWEDD
DSADASDSADSA
[[email protected] bin]#
[[email protected] bin]#
[[email protected] bin]# awk -F "" '{print $1}' 3
e
e
f
D
6、实现字符串翻转
[[email protected] bin]# cat 8
qweqewqedadaddas
[[email protected] bin]# rev 8
saddadadeqweqewq
########################################第2次电面
7、sed awk grep哪个最好
我答的是 哪个掌握的精通,都很好,但是还是问我哪个最好,我只能说awk了,对于行操作和列操作都可以操作的很好。
8、grep -E -P 是什么意思
我说的是-E, --extended-regexp 采用规则表示式去解释样式。 -P不太清楚
9、还问了我对运维这个工作的理解,和应该具备的素质。
…………

后记:百度面试的这些日子,很刻苦的学习了一个阶段。脚本编写能力有了很大的提高。但是还是很遗憾,没有去到那。打算在大连找个运维的工作,继续我的理想。工作几年之后,我还会继续努力的。
3年前,我是个连电脑开机关机都不会的农村孩子,现在我感觉自己已经对于Linux入门了,我很有成就感,但是我还是被百度通知,我没有发展潜力。我是东软的学生,我总是认为计算机这个行业不看
出身,只要有实力就可以了。但是第一次电面我没有被提前通知会电面,突然打来的电话,当时正在睡觉,头脑一片空白……进入到第2次面试的时候,没有慌张准备的很充分,但是还是没有最终被录取。
面试的考官问我,你最失落的事是什么,我说我最失落的事是我高考前意外受伤休学了,我现在才意识到,我当时应该回答他,我最失落的时刻应该是我得知被百度拒绝的那一刻。
已经付出了努力,即使失败也很坦然。

Git入门教程

考虑到CVS的一些局限性,最近和同事在公司推行Git。

其实,如果推行SVN的化,可能推行的难度会降低很多。不过lark说既然推行一个新的版本管理工具,总要花费一定的时间进行培训、部署、转换。而推行Git和SVN的代价不如想象中差距那么大。因此,不如就多花些精力推行Git , 可以带来更多的好处。 这个想法说服了我。 然后就开始筹备了。 我发现网上很多git教程对一些基础命令(比如git-reset)的介绍还是不够清楚。另外,介绍git1.5的少,介绍git1.4的多。此外,对于如何基于Git合作开发,介绍的内容也是少之又少。因此,决定写一份教程,以减少在公司推广Git的培训代价。

其实我也是一个Git的新手。 写这份教程也是我自己学习和摸索git的过程,其中基于Git进行合作开发的模式参考了CVS,应该是很初级的合作模式。但是当前自己也只能做到这一步了。 教程所述都是自己通过试验验证的。至少可以满足公司基本的合作开发。教程写完后,谢欣说可以放到blog与大家共享。我觉得是个不错的主意。一方面我觉得这个文档应该可以给git的新手一些帮助,另一方面也欢迎git的大牛指点。 这里要感谢《Git 中文教程》的作者。还有概述中关于git的优点描述拷贝了网络上某位大牛的原话,但是拷贝的出处也是转载的,就在这里谢谢那位我不知名大牛了。

下面就开始了。

1. 概述
对于软件版本管理工具,酷讯决定摒弃CVS而转向Git了。
为什么要选择Git? 你真正学会使用Git时, 你就会觉得这个问题的回答是非常自然的。然而当真正需要用文字来回答时,却觉得文字好像不是那么够用。 咳,该则么回答呢?
其实,关键的问题不在于如何回答这个问题。 问题的关键是公司已经决定使用它了。那么,我们的程序员们! 请开动你们的浏览器,请拿出你的搜索引擎工具,去自己发掘答案吧。在这里,我只能给你们一个最朦胧的感觉。
Git和 CVS、SVN不同,是一个分布式的源代码管理工具。Linux内核的代码就是用Git管理的。它很强,也很快。它给我们带来的直接好处有:
1. 傻瓜都会的初始化,git init, git commit -a, 就完了。对于随便写两行代码就要放到代码管理工具里的人来说,再合适不过。也可以拿git做备份系统,或者同步两台机器的文档,都很方便。
2. 绝大部分操作在本地完成,不用和集中的代码管理服务器交互,终于可以随时随地大胆地check in代码了。 只有最终完成的版本才需要向一个中心的集中的代码管理服务器提交。
3. 每次提交都会对所有代码创建一个唯一的commit id。不像CVS那样都是对单个文件分别进行版本的更改。所以你可以一次性将某次提交前的所有代码check出来,而不用考虑到底提交过那些文件。(其实SVN也可以做到这点)
4. branch管理容易多了,无论是建立新的branch,还是在branch之间切换都一条命令完成,不需要建立多余的目录。
5. branch之间merge时,不仅代码会merge在一起,check in历史也会保留,这点非常重要。
6. … 太多了
当然,Git也会带给我们一些困难,首先,你想要使用好git,就要真正明白它的原理,理解它的观念, 对以那些CVS的熟手来说,改变你已经固有的纯集中式源代码管理的观念尤为重要,同时也会让你觉得有些困难。在使用git的初期,你可能会觉得有些困难,但等你逐渐明白它时,你绝对会喜欢上它。这是一定的,就像我问你“喜欢一个温吞如水、毫无感觉的主妇,还是喜欢一个奔放如火,让你爱的痴狂恨的牙痒的情人”一样毋庸置疑。
下面,就让我们进入学习Git之旅…
请记住,这只是一个非常简单而且初级的教程, 想要成为git的专家,需要各位同事不断的自己深入挖掘。
2. Git基础命令

2.1 创建Git库—git-init
你们曾经创建过CVS的库么?应该很少有人操作过吧?因为很多人都是从CVS库里checkout代码。同样,在合作开发中,如果你不是一个代码模块的发起者,也不会使用到这个命令,更多的是使用git-clone(见2.7节)。 但是,如果你想个人开发一个小模块,并暂时用代码管理工具管理起来(其实我就常这么做,至少很多个人开发过程都可以保留下来,以便备份和恢复),创建一个Git库是很容易和方便的。
对于酷讯来说,当一个代码的Git库创建后,会添加代码文件到库里,并将这个库放到公司一个专门用来进行代码管理的服务器上,使大家可以在以后clone(不明白?没关系,继续往后看就明白了)它。对于个人来说,你可以随便将这个库放到哪里,只要你能访问的到就行。

创建一个Git库是很容易和方便的,只要用命令 git-init 就可以了。在Git1.4之前(包括git1.4)的版本,这个命令是git-init。
a) $ mkdir dir
b) $ cd dir
c) $ git-init
这样,一个空的版本库就创建好了,并在当前目录中创建一个叫 .git 的子目录。以后,所以的文件变化信息都会保存到这个目录下,而不像CVS那样,会在每个目录和子目录下都创建一个讨厌的CVS目录。
在.git目录下有一个config文件, 需要我们添加一下个人信息后才能使用。否则我们不能对其中添加和修改任何文件。
原始的config文件是这样的,
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
我们需要加入
[user]
name = xxx
emai= [email protected]
现在已经创建好了一个 git 版本库,但是它是空的,还不能做任何事情,下一步就是怎么向版本库中添加文件了。如果希望忽略某些文件,需要在git库根目录下添加. gitignore文件。
2.2 一条重要的命令 -- git-update-index
在介绍如何向git库中添加文件前,不得不先介绍git-update-index命令。这条命令可能会使很多熟悉CVS的用户疑惑, 一般来说,我们向一个源代码管理库提交代码的更改,都会抽象为以下的动作:更改文件;向源码管理系统标识变化;提交。比如从一个CVS库里删除一个文件,需要先删除文件,然后cvs delete; 最后cvs commit。
因此, git-update-index就是向源码管理系统标识文件变化的一个抽象操作。说的简要一些,git-update-index命令就是通知git库有文件的状态发生了变化(新添、修改、删除等待)。这条命令在早期的git版本中是非常常用的。 在新的git版本(1.5版本及以后)已经被其它命令包装起来,并且不推荐使用了。
git-update-index最常用的方式有以下两种,更多功能请man git-update-index。
 方法一:git-update-index --add 文件名列表。 如果文件存在,则这条命令是向git库标识该文件发生过变化(无论是否该文件确实被修改过),如果文件不存在,则这条命令是向git库表示需要加入一个新文件。
 方法二: git-update-index --force-remove 文件名列表。 这表示向git库表示哟啊从库中删除文件。无论该文件是否已经被删除,这条命令仅仅是通知git库要从库中删除这些文件。这些文件都不会受影响。
因此,git-update-index仅仅是向git库起到一个通知和标识的作用,并不会操作具体的文件。
2.3 向git库中添加或删除文件 – git-add、git-rm
其实,说使用git-add命令向git库里添加文件是不对的, 或者说至少是不全面的。git-add 命令的本质是命令"git-update-index --add” 的一个包装。因此,git-add除了可以添加文件,还可以标识文件修改。在调用了git-add后,才可以做commit操作。git-rm 也是一样, 它是git-update-index --force-remove的一个包装。
对于git-add来说, 如果在一个目录下调用了git-add * ,则默认是递归将子目录中所有文件都add到git库中。对于git-rm来说,也是一样。 这点和CVS有较大区别。
此外,我们还可以通过命令git-ls-files来查看当前的git库中有那些文件。

2.4 查看版本库状态—git-status
通过该命令,我们可以查看版本库的状态。可以得知那些文件发生了变化,那些文件还没有添加到git库中等等。 建议每次commit前都要通过该命令确认库状态。以避免误操作。
其总,最常见的误操作是, 修改了一个文件, 没有调用git-add通知git库该文件已经发生了变化就直接调用commit操作, 从而导致该文件并没有真正的提交。如果这时如果开发者以为已经提交了该文件,就继续修改甚至删除这个文件,那么修改的内容就没有通过版本管理起来。如果每次在提交前,使用git-status查看一下,就可以发现这种错误。因此,如果调用了git-status命令,一定要格外注意那些提示为“Changed but not updated:”的文件。 这些文件都是与上次commit相比发生了变化,但是却没有通过git-add标识的文件。
2.5 向版本库提交变化 – git-commit
直接调用git-commit命令,会提示填写注释。也可以通过如下方式在命令行就填写提交注释:git-commit -m "Initial commit of gittutor reposistory"。 注意,和CVS不同,git的提交注释必须不能为空。否则就会提交失败。
git-commit还有一个 –a的参数,可以将那些没有通过git-add标识的变化一并强行提交,但是不建议使用这种方式。
每一次提交,git就会为全局代码建立一个唯一的commit标识代码,用户可以通过git-revert命令恢复到任意一次提交时的代码。 这比CVS不同文件有不同的版本呢号管理可方便多了。(和SVN类似)
如果提交前,想看看具体那些文件发生变化,可以通过git-diff来查看, 不过这个命令的输出并不友好。因此建议用别的工具来实现该功能。在提交后,还可以通过git-log命令来查看提交记录。
2.6 分支管理 – git-branch
我们迎来了git最强大,也是比CVS、SVN强大的多的功能 — 分支管理。
大概每个程序员都会经常遇到这样的情况:
1. 需要立刻放下手头的工作,去修改曾经一个版本的bug并上线,然后再继续当的工作。
2. 本想向中心库commit一个重要修改,但是由于需要经常备份代码,最终不得不频繁的向中心库commit。从而导致大量无用的commit信息被保留在中心库中。
3. 将一次修改提交同事进行code review, 但是由于同事code review比较慢, 得到反馈时,自己的代码已经发生了变化,从而倒是合并异常困难
这些场景,如果用CVS或者SVN来解决,虽说不一定解决不了,但过程之繁琐,之复杂,肯定另所有人都有生不如死的感觉吧!究其关键,就是CVS或者SNV的branch管理太复杂,基本不具可用性。
在 git 版本库中创建分支的成本几乎为零,所以,不必吝啬多创建几个分支。当第一次执行git-init时,系统就会创建一个名为”master”的分支。 而其它分支则通过手工创建。下面列举一些常见的分支策略,这些策略相信会对你的日常开发带来很大的便利。
 1.创建一个属于自己的个人工作分支,以避免对主分支 master 造成太多的干扰,也方便与他人交流协作。
 2.当进行高风险的工作时,创建一个试验性的分支,扔掉一个烂摊子总比收拾一个烂摊子好得多。
 3.合并别人的工作的时候,最好是创建一个临时的分支用来合并,合并完成后在“fatch”到自己的分支(合并和fatch后面有讲述,不明白就继续往下看好了)
2.6.1 查看分支 – git-branch
调用git-branch可以查看程序中已经存在的分支和当前分支
2.6.2 创建分支 – git-branch 分支名
要创建一个分支,可以使用如下方法:
1. git-branch 分支名称
2. git-checout –b 分支名
使用第一种方法,虽然创建了分支,但是不会将当前工作分支切换到新创建的分支上,因此,还需要命令”git-checkout 分支名” 来切换, 而第二种方法不但创建了分支,还将当前工作分支切换到了该分支上。
另外,需要注意,分支名称是有可能出现重名的情况的, 比如说,我在master分支下创建了a和b两个分支, 然后切换到b分支,在b分支下又创建了a和c分支。 这种操作是可以进行的。 此时的a分支和master下的a分支实际上是两个不同的分支。 因此,在实际使用时,不建议这样的操作,这样会带来命名上的疑惑。
2.6.3 删除分支 – git-branch –D
git-branch –D 分支名可以删除分支,但是需要小心,删除后,发生在该分支的所有变化都无法恢复。
2.6.4 切换分支 – git-checkout 分支名
如果分支已经存在, 可以通过 git-checkout 分支名 来切换工作分支到该分支名
2.6.5 查看分支历史 –git-show-branch
调用该命令可以查看分支历史变化情况。 如:
* [dev1] d2
! [master] m2
--
* [dev1] d2
* [dev1^] d1
* [dev1~2] d1
*+ [master] m2
在上述例子中, “--”之上的两行表示有两个分支dev1和master, 且dev分支上最后一次提交的日志是“d2”,master分支上最后一次提交的日志是”m2”。 “--”之下的几行表示了分支演化的历史,其中 dev1表示发生在dev分支上的最后一次提交,dev^表示发生在dev分支上的倒数第二次提交。dev1~2表示发生在dev分支上的倒数第三次提交。
2.6.6 合并分支 – git-merge
git-merge的用法为:git-merge “some memo” 合并的目标分支 合并的来源分支。如:
git-merge master dev1~2
如果合并有冲突,git会由提示,当前,git-merge已经很少用了, 用git-pull来替代了。
用法为:git-pull 合并的目标分支 合并的来源分支。 如git-pull . dev1^

2.7 远程获取一个git库 git-clone
在2.1节提到过,如果你不是一个代码模块的发起者,也不会使用到git-init命令,而是更多的是使用git-clone。通过这个命令,你可以从远端完整获取一个git库,并可以通过一些命令和远端的git交互。
基于git的代码管理的组织结构,往往形成一个树状结构,开发者一般从某个代码模块的管理者的git库通过git-clone取得开发环境,在本地迭代开发后,再提交给该模块的管理者,该模块的管理者检查这些提交并将代码合并到自己的库中,并向更高一级的代码管理者提交自己的模块代码。
对于酷讯来说,公司会有一个中心的git库, 大家在开发时,都是从中心库git-clone获取最新代码。
git-clone的使用方法如下: git-clone [ssh://][email protected]:path。 其中, “ssh://”可选,也有别的获取方式,如rsync。 Path是远端git的根路径,也叫repository。
通过git-clone获取远端git库后,.git/config中的开发者信息不会被一起clone过来。仍然需要为.git/config文件添加开发者信息。此外,开发者还需要自己添加. gitignore文件
另外,通过git-clone获取的远端git库,只包含了远端git库的当前工作分支。如果想获取其它分支信息,需要使用”git-branch –r” 来查看, 如果需要将远程的其它分支代码也获取过来,可以使用命令” git checkout -b 本地分支名 远程分支名”,其中,远程分支名为git-branch –r所列出的分支名, 一般是诸如“origin/分支名”的样子。如果本地分支名已经存在, 则不需要“-b”参数。

2.8 从远程获取一个git分支 – git-pull
与git-clone不同, git-pull可以从任意一个git库获取某个分支的内容。用法如下:
git-pull [email protected]: 远端repository名 远端分支名:本地分支名。这条命令将从远端git库的远端分支名获取到本地git库的一个本地分支中。其中,如果不写本地分支名,则默认pull到本地当前分支。
需要注意的是,git-pull也可以用来合并分支。 和git-merge的作用相同。 因此,如果你的本地分支已经有内容,则git-pull会合并这些文件,如果有冲突会报警。

2.9 将本地分支内容提交到远端分支 – git-push
git-push和git-pull正好想反,是将本地某个分支的内容提交到远端某个分支上。用法:
git-push [email protected]: 远端repository名 本地分支名:远端分支名。这条命令将本地git库的一个本地分支push到远端git库的远端分支名中。

需要格外注意的是,git-push好像不会自动合并文件。这点我的试验表明是这样,但我不能确认是否是我用错了。因此,如果git-push时,发生了冲突,就会被后push的文件内容强行覆盖,而且没有什么提示。 这在合作开发时是很危险的事情。
2.10 库的逆转与恢复 – git-reset
库的逆转与恢复除了用来进行一些废弃的研发代码的重置外,还有一个重要的作用。比如我们从远程clone了一个代码库,在本地开发后,准备提交回远程。但是本地代码库在开发时,有功能性的commit,也有出于备份目的的commit等等。总之,commit的日志中有大量无用log,我们并不想把这些log在提交回远程时也提交到库中。 因此,就要用到git-reset。
Git-reset的概念比较复杂。它的命令形式:git-reset [--mixed | --soft | --hard] [<commit-ish>]
命令的选项:
--mixed
这个是默认的选项。 如git-reset [--mixed] dev1^(dev1^的定义可以参见2.6.5)。它的作用仅是重置分支状态到dev1^, 但是却不改变任何工作文件的内容。即,从dev1^到dev1的所有文件变化都保留了,但是dev1^到dev1之间的所有commit日志都被清除了,而且,发生变化的文件内容也没有通过git-add标识,如果您要重新commit,还需要对变化的文件做一次git-add。 这样,commit后,就得到了一份非常干净的提交记录。
--soft
相当于做了git-reset –mixed,后,又对变化的文件做了git-add。如果用了该选项, 就可以直接commit了。
--hard
这个命令就会导致所有信息的回退, 包括文件内容。 一般只有在重置废弃代码时,才用它。 执行后,文件内容也无法恢复回来了。

2.11 更多的操作
之前的10节只简要介绍了git的基本命令,更多的细节可以去linux下man git的文档。此外,http://www.linuxsir.org/main/doc/git/gittutorcn.htm 也有不少更详细的介绍。

3. 基于git的合作开发
对于酷讯来说,当我们采用了Git,如何进行合作开发呢? 具体步骤如下:
3.1 获取最新代码

酷讯会准备一个中心git代码库。首先,我们将整理好的代码分模块在git中心库中建立git库。并将文件add到中心库中。 接下来,开发者通过git-clone将代码从中心库clone到本地开发环境。
对于较大的项目,我们还建议每个组选择一个负责人,由这个负责人负责从中心库获取和更新最新的代码,其它开发者从这个负责人的git代码库中clone代码。此时,对开发者来说,这个负责人的git库就是中心库了。

3.2 开发者在本地进行迭代开发

当用户将代码clone到本地后, 就可以进行本地的迭代开发,建议用户不要在master分支上开发,而是建立一个开发分支进行开发。 在本地开发中,用户可以随意的创建临时分支,随意commit。

3.3 开发者请其它同事进行code review

当本地开发完毕,可以请其它同事进行code review。过程为:
1. user2通通过git-pull命令,将开发者(user1)的开发分支(dev)pull到user2本地的一个tmp分支,并切换工作分支到该分支上进行code review。
2. 完成code review后, user2切换回其原有开发分支继续开发,并告知user1已经修改完毕。
3. User1将user2的tmp分支git-pull到本地tmp分支,并和dev分支进行merge。最终得到一个code review后的dev分支。
当然,user2也可以直接坐在user1旁边在他的代码上进行review。而不需要走上述步骤。(图中第7步,不是git-pull,而是直接在dev分支上和user1边review边modify)

3.4 和中心库进行代码合并

使用过CVS的人都知道, 在commit之前,都要做一次cvs update,以避免和中心库冲突。Git也是如此。
现在我们已经经过了code review, 准备向中心库提交变化了, 在开发的这段时间,也许中心库发生了变化, 因此,我们需要在向中心库提交前,再次将中心库的master分支git-pull到本地的master分支上。并且和dev分支做合并。最终,将合并的代码放入master分支。
如果开发过程提交日志过多,可以考虑参照2.10节的介绍做一次git-reset。
此外,如果发现合并过程变化非常多, 出于代码质量考虑,建议再做一次code review

3.5 提交代码到中心库

此时,已经完全准备好提交最终的代码了。 通过git-push就可以了。

3.6 合作流程总结
大家可以看到,使用git进行合作开发,这一过程和CVS有很多相似性,同时,增强了以下几个环节:
1. 开发者在本地进行迭代开发,可以经常的做commit操作且不会影响他人。 而且即使不在线也可以进行开发。只需要最后向中心库提交一次即可。
2. 大家都知道,如果CVS管理代码,由于我们会常常做commit操作。但是在commit之前cvs update时常会遇到将中心库上的其它最新代码checkout下来的情况,此时,一旦出现问题,就很难确认到底是自己开发的bug还是其它用户的代码带来了影响。 而使用git则避免了用户间的开发互相影响。
3. 更有利于在代码提交前做code review。 以往用cvs, 都是代码提交后才做code view。如果发生问题, 也无法避免服务器上有不好的代码。 但是用git, 真正向中心库commit前,都是在本地开发,可以方便的进行code review, 然后才提交到中心库。更有利于代码质量。而且, 大家应该可以感到,使用git的过程中,更容易对代码进行code review,因为影响因素更小。
4. 创建多分支,更容易在开发中进行多种工作,而使工作间不会互相影响。 比如user2对user1的代码进行code review时,就可以非常方便的保留当时的开发现场,并切换到user1的代码分支,在code review完毕后,也可以非常方便的切换会曾经被中断的工作现场。

诚然,带来这些好处的同时,确实也使得操作比CVS复杂了一些。但我们觉得和前面所能获得的好处相比,这些麻烦是值得的。 当大家用惯了之后会发现,这并不增加多大的复杂性, 而且开发流程会更加自然。

请大家多动手,多尝试! 去体验git的魅力所在吧!let’s enjoy it!