shell批量替换文件扩展名

8 10 月, 2011 by edsionte 12 comments »

早上本想将一些照片上传到相册中,但是由于所有照片的扩展名都是JPG而不是小写的jpg,因此造成了“格式不正确”而不能上传照片。此刻就产生了这样一个问题:使用shell脚本如何批量将所有文件的扩展名JPG都改成小写的jpg?

既然要批量替换文件名,那么肯定得用一个for循环依次遍历指定目录下的每个文件。对于每个文件,假如该文件的名称为name.oldext,那么我们必须原始文件名中挖出name,再将它与新的文件扩展名newext拼接形成新的文件名name.newext。依照这样的思路,就诞生了下面的脚本:

#!/bin/bash
oldext="JPG"
newext="jpg"

dir="/home/edsionte/mypic"
cd $dir

for file in $(ls $dir | grep .$oldext)

	do
	name=$(ls $file | cut -d. -f1)
	mv $file ${name}.$newext
	done

下面对针对这个程序作简单说明:

1.变量oldext和newext分别指定旧的扩展名和新的扩展名。dir指定文件所在目录;

2.“ls $dir | grep .$oldext”用来在指定目录dir中获取扩展名为旧扩展名的所有文件;

3.在循环体内先利用cut命令将文件名中“.”之前的字符串剪切出来,并赋值给name变量;接着将当前的文件名重命名为新的文件名。

通过这个脚本,所有照片的扩展名都成功修改。为了使这个脚本更具有通用型,我们可以增加几条read命令实现脚本和用户之间的交互。改进版的脚本如下:

#!/bin/bash

read -p "old extension:" oldext
read -p "new extension:" newext
read -p "The directory:" dir
cd $dir

for file in $(ls $dir | grep .$oldext)

	do
	name=$(ls $file | cut -d. -f1)
	mv $file ${name}.$newext
	echo "$name.$oldext ====> $name.$newext"
	done
echo "all files has been modified."

修改后的脚本可以批量修改任意扩展名。done。

shell中的环境变量和自定义变量

6 10 月, 2011 by edsionte 无评论 »

Shell中的变量可以简单分为环境变量和自定义变量。环境变量有时也被称为全局变量,它是操作系统为Shell事先定义的一组变量,这些变量共同描述了当前Shell运行的系统环境;而自定义变量则是用户根据所需而定义的变量,它也被称为局部变量。为了区分两者的不同,环境变量通常用大写字母表示,而自定义变量通常使用小写子母表示。

1.环境变量

环境变量是一组变量的集合,它们描述了当前Shell运行的环境信息。最典型的环境变量即为PATH,它描述了可执行文件的路径信息。通过env命令可以查看当前Shell环境下所有环境变量及其内容。

edsionte@edsionte-desktop:~$ env
TERM=xterm
SHELL=/bin/bash
USER=edsionte
USERNAME=edsionte
PATH=/home/edsionte/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/edsionte/bin
PWD=/home/edsionte

…………

下面对部分环境变量做以解释:

HOME:表示当前用户的主目录。当输入cd或cd ~命令时,就会用到这个变量,如果更改了这个变量的值,那么使用上述命令的结果也会相应的改变。

SHELL:表示当前的shell环境所使用的shell程序。常见的shell程序有/bin/bash和/bin/sh,Linux中默认使用的是/bin/bash。

PWD:shell当前所在的工作目录,这个变量的值是通过pwd命令得到的。

USER:当前的用户名。

2.自定义变量

Shell除了环境变量,还包括用户自定义的变量。env命令查看的只是所有环境变量,而set命令既可以查看环境变量也可以查看自定义变量。比如:

edsionte@edsionte-desktop:~$ myvar=test
edsionte@edsionte-desktop:~$ env | grep myvar
edsionte@edsionte-desktop:~$ set | grep myvar
myvar=test

3.环境变量和自定义变量之间的转换

环境变量有在Linux下的shell程序默认为Bash,因此每一个Bash其实都是一个进程,在当前Bash下输入ps命令则可以查看该Bash的PID。对于环境变量而言,每个Bash进程都可以对其进行引用;而对于用户自定义的变量,只有对其定义的Bash进程可以引用它,其他的Bash进程甚至是其子进程均不可以引用。这也是环境变量和自定义变量的的主要区别之一。

从进程内存映像的结构分布可以很好的解释环境变量和自定义变量之间的差异。在Linux系统中,所有的Bash进程都是gnome-terminal进程的孩子或孙子,而gnome-terminal进程是由init进程创建的,由于环境变量保存在gnome-terminal进程的数据段,因此它的孩子或孙子(即Bash进程的孩子)均可以继承数据段的数据,即所有Bash进程都可以访问环境变量。对于自定义变量而言,它位于每个Bash进程的栈中,而每个进程它都有自己独立的段,因此自定义变量是不能被继承的,即自定义变量不能被其他bash进程引用。

那么,环境变量和自定义变量之间如何相互转换呢?通过export命令和declare命令即可完成。如果要将一个自定义变量转化为环境变量,则需要使用下述命令:

edsionte@edsionte-desktop:~$ myvar=test
edsionte@edsionte-desktop:~$ env | grep myvar
edsionte@edsionte-desktop:~$ export myvar
edsionte@edsionte-desktop:~$ env | grep myvar
myvar=test

如果要将环境变量转化为自定义变量,则需使用下述命令:

edsionte@edsionte-desktop:~$ declare +x myvar
edsionte@edsionte-desktop:~$ env | grep myvar
edsionte@edsionte-desktop:~$ echo $myvar
test

关于exprot和declare命令更多的用法,可以参考man手册。

inotify机制在内核态下的使用方法

5 10 月, 2011 by edsionte 无评论 »

inotify是一种使用简单而功能强大的文件系统事件监控机制。在用户态下通过一组简单的系统调用即可使用inotify机制监控文件的变化,而在内核态中也可以通过一组API来inotify机制。

1.创建并初始化inotify实例

为了在内核中使用inotify机制,必须首先创建并初始化一个inotify实例,每个inotify实例其实对应的是一个数据结构inotify_handle。

struct inotify_handle {
	struct idr		idr;		/* idr mapping wd -> watch */
	struct mutex		mutex;		/* protects this bad boy */
	struct list_head	watches;	/* list of watches */
	atomic_t		count;		/* reference count */
	u32			last_wd;	/* the last wd allocated */
	const struct inotify_operations *in_ops; /* inotify caller operations */
};

创建并初始化一个inotify实例的过程其实就是分配并初始化一个inotify_handle结构,这个过程通过inotify_init()完成。此外,每个inotify实例都与一个inotify_operations结构相关联,该结构中有两个钩子函数,分别定义了事件处理和销毁watch两个函数的接口,这两个钩子函数应该根据具体的应用场景来实现。

struct inotify_operations {
	void (*handle_event)(struct inotify_watch *, u32, u32, u32,
			     const char *, struct inode *);
	void (*destroy_watch)(struct inotify_watch *);
};

一个inotify_init()通用的使用方法如下:

struct inotify_operations *ops;
ops->handle_event = my_handle_event;
ops->destroy_watch = my_destroy_watch;
struct inotify_handle *ih = inotify_init(ops);

也就是说,通过向inotify_init()中传入一个inotify_operations结构的变量来实现钩子函数和inotify实例之间的关联。

2.添加watch

从inotify实例所对应的数据结构inotify_handle中可以看出,每个inotify实例都拥有一个由watch组成的链表。该双链表上的每个watch即代表该inotify实例所监控的对象,这个对象可能是文件,也可能是目录。每个watch在内核中的表示如下:

struct inotify_watch {
	struct list_head	h_list;	/* entry in inotify_handle's list */
	struct list_head	i_list;	/* entry in inode's list */
	atomic_t		count;	/* reference count */
	struct inotify_handle	*ih;	/* associated inotify handle */
	struct inode		*inode;	/* associated inode */
	__s32			wd;	/* watch descriptor */
	__u32			mask;	/* event mask for this watch */
};

该结构中每个字段的含义如下:

h_list:一个inotify实例中所有watch组成一个双链表,h_list表示当前watch在该双链表中所处的结点。该双链表的表头即为inotify_handle结构中的watches字段。

i_list:一个文件可能被多个inotify实例监控,而被监控一次就产生一个watch,该文件对应的所有watch组成一个双链表,i_list表示当前watch在该双链表中所处的结点。该双链表的表头即为inode结构中的inotify_watches字段。

count:表示该watch被引用的次数。

ih:每个watch必然属于某个inotify实例,该字段指向当前watch所属的inotify_handle结构。

inode:该字段指向当前watch所关联的文件的inode。

wd:表示当前watch的文件描述符。

mask:表示当前监控对象所对应的事件掩码。

当初始化完一个inotify实例后,通过inotify_add_watch()即可向该实例中添加watch。不过在添加前还需通过inotify_init_watch()对每个watch进行初始化。

对watch初始化完成的主要工作即初始化两个链表结点、该watch的引用计数等。向inotify实例添加一个watch主要完成的工作即为向两个watch链表中添加当前的watch结点,并且更新watch的引用计数等。

3.删除一个watch

从指定的inotify实例中删除一个watch所完成的工作其实和添加watch的过程相反,通过inotify_rm_watch()即可完成。

4.对监控事件的处理

handle_event()通常并不对具体的监控对象做处理,而是作为所有监控事件的入口点;接着根据每个事件的掩码做出“分流”动作,即对具体的监控事件做以处理。

动态的进程

29 9 月, 2011 by edsionte 2 comments »

进程是一个动态的实体,它是程序的一次执行过程,是操作系统中资源分配的基本单位。程序和进程的最大区别在于进程是动态运行着的,它存在于内存中;程序是静态的,它存在于磁盘上。

这里的程序指的是可执行文件(并不包含脚本文件),通常我们所说的源程序要通过预编译、编译、汇编和链接四个步骤转化为可执行程序。当我们运行可执行程序时,操作系统将可执行程序读入内存,程序摇身一变转化为一个进程。

1.进程的状态

进程是一个活体,因此也就随之诞生了进程的状态。在Linux内核中,几种经典的进程状态如下:

可运行状态:表示进程正在运行或者正在等待被运行,也就是操作系统原理中的运行态和就绪态。Linux使用TASK_RUNNING宏表示此状态。

可中断的等待状态:进程正在等待某个事件完成,即操作系统原理中等待态(或阻塞态、睡眠态)。处于该状态的进程属于“轻度睡眠”,它可以被信号或者定时器唤醒。Linux中使用TASK_INTERRUPTIBLE来表示此状态。

不可中断的等待状态:也是一种等待状态,只不过处于该状态的进程处于“深度睡眠”,它不能被信号或者定时器唤醒,只有当其等待的事件发生时才可以被唤醒。Linux中使用TASK_UNINTERRUPTIBLE来表示该状态。

僵死状态:进程已经终止,但是它的进程描述符仍然没有被操作系统收回,此时的进程只有身躯并无灵魂,需要父进程通过wait族函数为其收尸。Linux中使用EXIT_ZOMBIE表示该状态。

停止状态:进程因为收到SIGSTOP等信号停止运行。Linux中使用__TASK_TRACED表示该状态。

除了上述几种经典状态外,可以在sched.h中查看其他几种进程的状态。我们通过ps命令在shell中查看当前系统所有进程的状态信息。比如:

edsionte@edsionte-desktop:~/linux-3.0.4$ ps -eo pid,stat,command
  PID STAT COMMAND
    1 Ss   /sbin/init
    2 S    [kthreadd]
    3 S    [migration/0]
    4 S    [ksoftirqd/0]
    5 S    [watchdog/0]
    6 S    [migration/1]
    7 S    [ksoftirqd/1]
    8 S    [watchdog/1]

每行依次显示的是进程的pid、进程当前的状态和进程名。ps命令所显示的进程状态通过一组字母符号来表示,各种符号的含义如下:

       D    Uninterruptible sleep (usually IO)
       R    Running or runnable (on run queue)
       S    Interruptible sleep (waiting for an event to complete)
       T    Stopped, either by a job control signal or because it is being traced.
       W    paging (not valid since the 2.6.xx kernel)
       X    dead (should never be seen)
       Z    Defunct ("zombie") process, terminated but not reaped by its parent.

2.进程的内存映像

在Linux中可执行文件(此处先忽略脚本文件)的格式为ELF,即Executable and Linking Format。虽然可执行文件是二进制文件,但是它的内部还是划分着一些区域,这些区域称为可执行文件的段。这里的段和X86体系架构中的段是两个完全不同的概念。

通常可执行文件包含一个文本段(代码段),数据段。有时候可执行文件中还额外包含一个BSS段,这个段中存放着那些在源程序中没有被初始化的全局变量。

当运行可执行文件时,内核将可执行文件读入内存,我们将读入内存中的可执行文件称之为进程的内存映像。进程的内存映像虽然也根据存放内容的不同将进程的虚拟地址空间划分为一块一块的,但是这些区域在内存中并不称之为段,而是虚拟内存区域,内核使用vm_area_struct结构来表示这片内存区域。

可执行文件和进程的内存映像虽然都有代码段和数据段,但两者其实是不同的。首先可执行文件(也就是程序)是静态的,存放在磁盘上,而进程的内存映像只有在程序运行时才产生;其次,可执行文件没有堆栈段,而进程的内存映像是包含堆栈段的,因为堆(heap)用于动态分配内存,而栈(stack)需要保存局部变量、临时数据和传递到函数的参数等。从这些不同点也可以说明程序是动态的。

可执行文件的段在进程地址空间中的分布图可以参考如下:

需要注意的是,进程的地址空间并不只包含一个文本段或数据段,由于大多数源程序的目标文件在链接时都需要链接一些动态库,最终形成可执行文件,因此进程的地址空间中会有好几个文本段和数据段区域。而且在链接过程中,还需要加入链接器(ld),因此进程地空间精确的示意图如下:

 

在一个进程的内存映像中,文本段用来存放二进制的可执行代码,而数据段用来存放全局变量和静态变量,BSS段用来存放未初始化的全局变量,堆段用于为malloc函数分配空间,栈段用来存放局部变量和形参等临时数据。

参考:

1. Linux C编程实战
2. C专家编程

inotify机制在用户态下的使用方法

24 9 月, 2011 by edsionte 2 comments »

1.inotify是什么?

inotify机制用于监控文件系统,通过它可以监控一个或多个文件,如果该文件发生了指定事件,比如打开,读或写等,该机制会异步的响应用程序发出通知(或称为警告),应用程序根据文件系统发生的事件类型做出相应的反应。

2.inotify可以监控的事件

inotify使用一组宏来表示文件可以被监控的事件,这些宏在稍候介绍的inotify_add_watch()中使用。在没有特别说明的情况下,下面解释中的文件均指被监控的文件,并且即可以是普通文件又可以是目录文件。

IN_ACCESS:文件被访问,如果是目录文件,则指目录中的文件名被访问。

IN_MODIFY:文件被修改,如果是目录文件,则指目录中的文件名被修改。

IN_ATTRIB:文件属性被修改,比如使用chmod命令。

IN_CLOSE_WRITE:可写的文件被关闭。

IN_CLOSE_NOWRITE:不可写文件被关闭。

IN_CLOSE:文件被关闭,它等同于(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)的效果。

IN_OPEN:文件被打开。

IN_MOVED_FROM:文件被移出监控区,比如使用mv命令将一个文件移出监控目录。

IN_MOVED_TO:文件(这个文件既可以是受监控的又可以是未受监控的)被移入监控区,比如使用mv和cp命令。

IN_MOVE:文件被移动,它等同于(IN_MOVED_FROM | IN_MOVED_TO)的作用效果。

IN_CREATE:在目录中创建一个新文件,比如touch或mkdir命令。

IN_DELETE:文件被删除,比如使用rm命令。

IN_DELETE_SELF:自删除,即一个可执行文件在执行时删除自己。

IN_MOVE_SELF:自移动,即一个可执行文件在执行时移动自己。

IN_UNMOUNT:宿主文件系统被 umount。

另外,IN_ISDIR宏用来判断被监控的文件是否为目录文件,该宏可以在应用程序对监控文件作监控处理时应用。

3.inotify用户态使用概述

inotify机制属于Linux在2.6.13之后增加的一个新特性,它属于dnotify机制的升级版。要使用inotify机制监控文件系统,那么必须先创建一个inotify的实例。由于Linux中的一切皆为文件,可以将inotify实例理解为一个“inotify类型的文件”,因此该实例会对应一个文件描述符,这也属于inotify优于dnotify的一大特性。

inotify机制的另一大特性即为监控程序对文件的监控不必轮询去查看,一旦监控的文件有指定的事件发生,它会异步通知监控程序,监控程序收到警告后会立马做出相应的响应。而在没有发生监控事件的时候,监控程序则一直处于阻塞状态。

这里的阻塞通过read()即可完成。当没有监控时间发生时,inotify实例中没有数据则read()阻塞;当有监控事件发生时,监控事件将被写入inotify实例中,此时read函数被唤醒读取该事件,监控程序根据读取的数据做出相应处理。这里的事件其实是通过字节流发送到inotify实例中的,因此可以通过read()函数来读取。为此,专门有一个数据结构来存储监控事件,即为struct inotify_event:

 struct inotify_event
struct inotify_event {
	__s32		wd;		/* watch descriptor */
	__u32		mask;		/* watch mask */
	__u32		cookie;		/* cookie to synchronize two events */
	__u32		len;		/* length (including nulls) of name */
	char		name[0];	/* stub for possible name */
}; 

该结构的定义位于用户态文件目录include/linux/inotify.h中,每个字段代表的含义如下:

wd:一个监视器(watch)的描述符,所谓监视器就是一个二元组(监视文件,事件掩码),其中事件掩码包含该文件被监视的所有事件。wd是通过inotify_add_watch()返回的,wd在此结构中与一个监视事件关联,即说明wd监视器上发生了当前inotify_event这个事件。

mask:该事件的类型即为当前结构中的mask,它是wd中所指定mask的一个子集。

len:表示当前结构中name的长度,但有时候name为了字节对齐会填充若干个0,因此len会大于等于name的长度。

name:表示监控文件的路径,这里通过GNU C中的0长度数组来表示变长的文件路径。

对inotify机制的典型使用方法如下:

1.创建并初始化一个inotify的实例,通过inotify_init()即可实现,该函数返回一个文件描述符。

2.添加一个或多个监控文件,即监视器,通过inotify_add_watch()即可实现,该函数就返回一个监视器的文件描述符。

3.循环等待监控事件的发生,通过循环read()inotify实例的fd即可实现。

4.如果有监控事件发生,则将fd中的字节流读取到inotify_event结构中,监控程序随之作适当处理,处理完毕后返回继续等待。

5.当不需要继续监控或收到某个代表监控结束的信号时,关闭inotify实例的文件描述符。

关于基本的使用流程还可以参考下图:

4.inotify用户态API

inotify的API都使用文件描述符,这样可以将监控粒度控制到单个文件,而dnotify机制的控制粒度则为单个目录。使用文件描述符更大的优势在于对inotify的操作也可以使用read()、close()、select()等这些传统的文件操作函数。

1.int inotify_init (void)

创建并初始化一个inotify实例,该函数返回一个文件描述符。可以认为这个函数是打开一个inotify类型的文件并返回该类型文件的描述符。

2.int inotify_add_watch (int __fd, const char *__name, uint32_t __mask)

增加监视文件(监视器),fd用于指明该文件被添加于哪个inotify实例,name用于指名该文件的路径,mask则指明了该文件所有的监控事件。该函数调用成功后返回一个监视器的描述符。

3.int inotify_rm_watch (int __fd, int __wd)

从fd中删除一个监视器,wd指名具体的监视器。

关于上述函数的详细的使用方法以及错误返回值等内容可以参考man手册。

参考:

IBM Developer Works:http://www.ibm.com/developerworks/cn/linux/l-ubuntu-inotify/index.html

windows 7 ultimate product key

windows 7 ultimate product key

winrar download free

winrar download free

winzip registration code

winzip registration code

winzip free download

winzip free download

winzip activation code

winzip activation code

windows 7 key generator

windows 7 key generator

winzip freeware

winzip freeware

winzip free download full version

winzip free download full version

free winrar download

free winrar download

free winrar

free winrar

windows 7 crack

windows 7 crack

windows xp product key

windows xp product key

windows 7 activation crack

windows7 activation crack

free winzip

free winzip

winrar free download

winrar free download

winrar free

winrar free

download winrar free

download winrar free

windows 7 product key

windows 7 product key