Bash 分类中的最新日记

bash上小数计算

| 暂无评论 | 暂无引用通告
使用bc进行计算,如:

result=$(echo "37 * 0.5" |bc)

对结果取整的话:

result_int=${result%.*}

也可以通过sed截去小数点后的值:

echo $result|sed 's/\..*//g'

如何获取进程的启动时间

| 暂无评论 | 暂无引用通告

作者: PuGuangH 原文链接: http://blog.sina.com.cn/s/blog_4d6f6219010009n7.html

PID=$1

JIFFIES=`cat /proc/$PID/stat | cut -d" " -f22`

UPTIME=`grep btime /proc/stat | cut -d" " -f2`

START_SEC=$(( $UPTIME + $JIFFIES / 100 ))

START_TIME=`date -d "1970-1-1 UTC $START_SEC seconds"`

echo $START_TIME

 

其中PID中要传入对应的进程ID

 

其中/proc/stat中的btime指的是系统的启动时间也就是boot time

对于一个具体的进程  /proc/$pid/stat中对应的第22项指的是该进程相对于系统启动以来的执行时间。

完善自己的管理脚本

| 暂无评论 | 暂无引用通告
  这几天频繁更新在线的程序,着实让我头疼。上午抽了些时间重新写了用于程序更新的脚本,脚本的功能并不复杂,但要让其更完善的工作,还需要花一点心思。

  所谓让脚本完善一点是指填加几个函数,在执行关键性命令时做出提示,在执行完后做一个简单的判断,并将结果打印出来,如果命令执行出错,脚本应及时退出。

  以下的几个定制的函数能让我们的脚本更像样儿。
  
#!/bin/sh

. /etc/init.d/functions

#测试前一条命令执行情况
function test_result(){
        if [ "$1" -eq 0 ]; then
                echo_success
        else
                echo_failure
                echo
                exit 0
        fi
        echo
}
function yesno(){
        echo -n "继续:[y/N]"
        read GETIT
        if [ "$GETIT" == n -o "$GETIT" == N ]; then
                echo "程序已退出"
                exit 1
        else
                :
        fi
}

function useage(){
        echo "$0 PROJECTNAME HOST1 HOST2 ..."
        exit 1
}


  在执行关键性命令时,先打印出命令行或命令的功能,然后运行yesno提示是否执行该命令,如:

        echo $COMMAND
        yesno
        eval $COMMAND

  这里的COMMAND变量已存储了命令行;运行完命令后记得测试运行结果:

        echo $COMMAND
        yesno
        eval $COMMAND
        RETVAL=$?
        echo -n "执行同步..."
        test_result $RETVAL

  我们会得到这样的结果:

执行同步...                                                [  确定  ]

  如果你不打算将命令行的输出打印到标准输出的话,可以这样写脚本:

        echo $COMMAND
        yesno
        echo -n "执行同步..."
        eval $COMMAND >/dev/null 2>&1
        RETVAL=$?
        test_result $RETVAL

    这样就会产生系统启动过程中,启动各种服务时的效果了。

  还有一点就是要记得写脚本的用法,因为也许几个星期后,你也会忘记自己所写脚本的用法。

  情况是这样的,我管理着一个集群,有时需要更新这集群上的项目,每次手动写循环很烦人,不停的搞键盘,很累人,下面这个脚本可以让我偷偷懒,同时也减少了出错的机率,其实我使用这个脚本一段时间了,前一段时间我的工作站出了问题,一不要心将分区表删了,丢了一些资料,包括运行这个脚本的环境。花了两个小时重新写了这个脚本,赶快贴出来,下次系统崩溃后还能用得上,呵呵!
  我将脚本命令为upfile.pl,放在/root/syncproject/目录下,同时这个目录下放着多个项目文件夹及一个log文件夹,远端主机上的/home/project/下存放有项目文件,我要保持本地/root/syncproject/目录下的项目是新的,然后运行脚本:
[root@supersun.biz syncproject]#./upfile.pl -h host1,host2 -p project1
  这样就可以更新host1和host2上的project1项目了,rsync生成的日志保存到log文件夹下。
  脚本很简单,但对于我来说挺实用。平时就应该简化自己的工作。

#!/usr/bin/perl
use strict;
use Getopt::Std;

#定义默认变量
use vars qw/
$LOCAL_PATH
$REMOTE_PATH
$LOG_PATH
@HOST_LIST
@PROJECTS
$PROJECT_NAME
/;
#本地的项目存储路径
#远端的项目存储路径
#日志存诸路径
#默认的主机列表
#可使用的项目名称
$LOCAL_PATH="/root/syncproject/";
$REMOTE_PATH="/home/project/";
$LOG_PATH="/root/syncproject/";
@HOST_LIST=qw/host1 host2 host3/;
@PROJECTS=qw/project1 project2/;

#定义命令行选项
#h 主机列表hosts
#p 项目名project

my %opts;

getopt("hp",\%opts);

#处理命令行传入的主机列表
@HOST_LIST=split /,/,$opts{h} if  defined $opts{h};
#检查命令行传入的项目名是否可用
if(defined $opts{p}) {
        $PROJECT_NAME=$opts{p};
        my %TEST_PROJECTS;
        @TEST_PROJECTS{@PROJECTS}=@PROJECTS;
        unless(exists $TEST_PROJECTS{$PROJECT_NAME}){
                print "错误的项目名:$PROJECT_NAME\n可用的项目名:@PROJECTS\n";
                useage();
        }
}else{
        print "项目名未定义\n";
        useage();
}

#生成命令行,并fork多进程进行更新

foreach my $HOST(@HOST_LIST){
        my $COMMAND="rsync -av --delete ".$LOCAL_PATH.$PROJECT_NAME."/ ".$HOST.":"
.$REMOTE_PATH.$PROJECT_NAME."/";
        if(fork){
                print "更新$HOST上的$PROJECT_NAME\n";
                print "Command:$COMMAND\n";
        }else{
                my $output=`$COMMAND`;
                if($? eq 0){
                        print "$HOST更新成功\n";
                        my $file=$LOG_PATH."log/".$HOST;
                        open FD,'>',$file;
                        print FD join "\n",map $_="$HOST:$_",split /\n/,$output;
                        print FD "\n";
                        close FD;
                }else{
                        print "$HOST更新失败\n";
                        print join "\n",map $_="$HOST:$_",split /\n/,$output;
                        print "\n";
                }
                exit;
        }
}

#等待子进程
1 while wait_a_kid;

#等待子进程的例程

sub wait_a_kid {
        my $pid=wait;
        return 0 if $pid<0;
        1
}

#使用说明

sub useage {
        die "$0 [-h host1,host2,host3...] -p PROJECT_NAME\n";
}

  在管理集群时要求集群上的结点的配置是完全相同或相似,通常需要每个节点上重复执行相同的命令,当然有一些任务或更改配置是可以通过编写脚本或用shell的for循环来完成,但写多了你就会觉得很累。
  multixterm让一切变的更简单,只需在中央窗口中输入命令,该命令就会在所有的主机上执行,如果想单独在一台服务器上执行命令,只需点击与其连接的xterm窗口,输入并执行命令。如果想在一组服务器上运行命令,可以点击菜单中"Edit"->"Active"选中服务器。

multixterm.jpg脚本下载地址:http://expect.nist.gov/example/multixterm
在运行之前确保系统已安装expect,如果没有安装可以参考:安装expect,然后更改脚本第一行:
#!/depot/path/expectk改为#!/usr/local/bin/expectk,当然你应该指定你系统中的expectk的路径。
1、使用CDPATH变量

  如同使用PATH变量中搜索命令一样,CDPATH用于指定cd命令搜索目录,就我个人而言,经常使用到/root和/root/private两个文件夹,因此,我的CDPATH这样设置:
[root@supersun.biz tmp]#echo $CDPATH
.:/root:/root/private/
  当我从别的目录跳转到/root/private/perl下时:
[root@supersun.biz tmp]#pwd
/root/tmp
[root@supersun.biz tmp]#cd perl
/root/private/perl
[root@supersun.biz perl]#

2、自己定义变量

  试调nagios,需要经常跳到/usr/local/nagios下,自定义NAGIOS变量在~/.bash_profile中:

export NAGIOS=/usr/local/nagios

[root@supersun.biz root]# cd $NAGIOS
[root@supersun.biz nagios]# pwd
/usr/local/nagios

  同样,在使用jboss时,经常跳到/home/jboss/server/default/deploy下,次数多了就会烦人的,因此设定变量DEPLOY为/home/jboss/server/default/deploy

一个简单的批量同步脚本

| 评论(2) | 暂无引用通告
为了方便同步多个主机的目录到备份服务器,写了如下脚本:

#!/usr/bin/perl
use strict;
use File::Spec;
use File::Basename;
use File::Path;
#设定存储路径
my $storedir="/backup/";
while(<DATA>){
        chomp;
        my ($host,$s_path)=split /\t/;
        my $project_name=fileparse($s_path);
        my $d_path=File::Spec->catfile($storedir,$host,$project_name);
        $s_path=$s_path."/";
        $d_path=$d_path."/";
        mkpath $d_path,1,0755 unless -d $d_path;
        my $cmdline="rsync -av --delete --rsh=\"ssh\" root\@$host\:".$s_path." ".$d_path;
        print "备份主机:$host   备份目录:$s_path\n";
        system ($cmdline);
}

__DATA__
host1   /home/www
host2   /home/bbs


脚本的功能非常简单,即生成简单的命令行,由system命令调用一个shell来执行这个命令来完成备份。

脚本中的__DATA__下定义了需要备份的主机和目录(以TAB分隔开),生成的备份保存在$storedir="/backup/"定义的目录中,该目录下建立以主机名命令的目录,每个主机名目录中为每个一项目名。
脚本需要完善的地方有:
1、没有生成日志;
2、没有保存多份不同时间的备份。

关于备份,你还可以参看一下以前的几篇文章:
2007.08.31: 备份几台服务器的/home分区
2007.08.21: MYSQL数据库导出导入
2007.08.07: 备份Firefox的书签
2007.07.31: 一个差分备份用的小脚本
2007.07.30: 备份技术及基本分类

另外要记得备份一下自己的主目录,只要运行一条命令就行,不然有一天电脑出问题,后悔莫及,<LINUX SERVER HACKS>里有一句说的非常好:唯一比灾难性的磁盘故障、失控的远程主机和险恶的安全性事件更糟糕的事,是发现这些事情本来可以避免时的那种痛彻心扉的感觉。
我的方法是写一个脚本,命名为:rootbackup.sh放入/root/bin下,下班时只要运行:
[root@supersun.biz ~]#rootbackup.sh
就可将/root目录同步到我的移动硬盘中。脚本内容:

#!/bin/sh
echo "开始对/root目录进行备份........"
echo "挂载移动硬盘:"
echo "mount /dev/sda4 /mnt"
mount /dev/sda4 /mnt
echo "进行同步"
rsync -av --delete /root /mnt/sun
echo "同步结束"


    此脚本用于可保文件内容的md5校验和及以文件stat信息以及与生成的校验数据进行对比,找好更动过的文件。脚本如下:

#!/usr/bin/perl
#
#用法:
#genmd5.pl --basedir=/etc --chksumfile=etc-chksum.dat
#genmd5.pl --basedir /private/etc --compare
use strict;

use Digest::MD5;

use IO::File;
use File::Find ();

use Getopt::Long;

#设置默认值
my $chksumfile = 'chksums.dat';
my $compare = 0;
my $basedir = '/etc';

use vars qw/*name *dir *prune/;
*name   = *File::Find::name;
*dir    = *File::Find::dir;
*prune  = *File::Find::prune;

GetOptions("chksumfile=s" => \$chksumfile,
           "compare" => \$compare,
           "basedir=s" => \$basedir);

my $chksumdata = {};

if ($compare)
{
    loadchksumdata($chksumfile);
}

my $outfile = '';

if (!$compare)
{
    $outfile = IO::File->new($chksumfile,"w");
}

File::Find::find({wanted => \&wanted}, $basedir);

if ($compare)
{
    foreach my $file (keys %{$chksumdata})
    {
        print STDERR "Couldn't find $file, but have the info on record\n";
    }
}

sub loadchksumdata
{
    my ($file) = @_;

    open(DATA,$file) or die "Cannot open check sum file $file: $!\n";
    while(<DATA>)
    {
        chomp;
        my ($filename,$rest) = split(/:/,$_,2);
        $chksumdata->{$filename} = $_;
    }
    close(DATA);
}

sub wanted {
    next unless (-f $name);

    my $fileinfo = genchksuminfo($name);

    if ($compare)
    {
        if (exists($chksumdata->{$name}))
        {
            if ($chksumdata->{$name} ne $fileinfo)
            {
                print STDERR "Warning: $name differs from that on record\n";
                gendiffreport($chksumdata->{$name}, $fileinfo);
            }
            delete($chksumdata->{$name});
        }
        else
        {
            print STDERR "Warning: Couldn't find $name in existing records\n";
        }
    }
    else
    {
        printf $outfile ("%s\n",$fileinfo);
    }
}

sub gendiffreport
{
    my ($orig,$curr) = @_;

    my @fields = qw/filename chksum device inode mode nlink uid gid size mtime ctime/;

    my @origfields = split(/:/,$orig);
    my @currfields = split(/:/,$curr);

    for(my $i=0;$i<scalar @origfields;$i++)
    {
        if ($origfields[$i] ne $currfields[$i])
        {
            print STDERR "\t$fields[$i] differ; was $origfields[$i],
                             now $currfields[$i]\n";
        }
    }

}

sub genchksuminfo
{
    my ($file) = @_;

    my $chk = Digest::MD5->new();

    my (@statinfo) = stat($file);

    $chk->add(@statinfo[0,1,2,3,4,5,7,9,10]);
    $chk->addfile(IO::File->new($file));
    return sprintf("%s:%s:%s",
                   $file,$chk->hexdigest,
                   join(':',@statinfo[0,1,2,3,4,5,9,10]));
}

用以下命令生成校验数据:

[root@supersun securety]# ./getsum.pl --basedir=/etc/ --chksumfile=etc-chksum.dat

etc-chksum.dat格式如下:

/etc/bluetooth/hcid.conf:c3fb848b5e2f57e3cd65ecd8dd766724:769:1627930:33188:1:0:0:1153336356:1163469800
/etc/bluetooth/pin:81bdf50f2025f988490024cfbd36ffb8:769:1627931:33152:1:0:0:1153336356:1163469800
校验文件:

[root@supersun securety]# ./getsum.pl --basedir=/etc --compare --chksumfile=etc-chksum.dat
Warning: /etc/fstab differs from that on record
        chksum differ; was 253f53fef12b9e6fa7bc2cb3556427de,
                             now a8506e1f2ff5e5dcb08d93b64b1be235
        inode differ; was 1629160,
                             now 1627820
        size differ; was 1187075582,
                             now 1190012212
        mtime differ; was 1187075582,
                             now 1190012212

原文请参见:http://www.ibm.com/developerworks/aix/library/au-satsystemvalidity/index.html 

写好脚本用于上传公钥

| 暂无评论 | 暂无引用通告

   就是因为懒!我不想每次上传公钥到新系统上时重复那几条命令,当然也是为了高效,呵呵!在使用脚本前请更改变量$locate_key的值,将其设定为你公钥所在文件。

#!/usr/bin/perl -w
#名称:pubkey
#用法:pubkey -h hostname [-u username]
use strict;
use Getopt::Std;

my %opt;
my $locate_key="/root/.ssh/pubkeys";
$opt{u}="root";
getopt("hu",\%opt);
print "pubkey -h hostname [-u username]\n",exit unless defined $opt{h};
`ssh $opt{u}\@$opt{h} "if [ -d .ssh ]; then  : ;else mkdir .ssh ;fi ;cd .ssh;cat >>authorized_keys" <$locate_key`;

为了更高效点的了解内网中macip的变更情况,我写了以下脚本,在此我们可以学到如果生成彩色的输出及如果使用数组和关联数组的混合以建立复杂的数据结构。

数据文件样式:

192.168.4.99    0       00:12:3f:d2:ef:e6       WORKGROUP\6B76C16DD9D3453 

我们可以使用以下命令生成原始的数据文件:

[root@supersun private]# nbtscan -m 192.168.4.0/24 |awk '{print $1"\t0\t"$3"\t"$2}' >data.mac

然后我们运行脚本,终端输出新增的IP地址及变更的数据并以红色字体打印,根据实际需要我们选择是否保存到数据文件中。

最新资源

  • IMG_1437.JPG
  • line.png
  • bar.png
  • perl_calander.jpg

关于此归档

这里是分类Bash中的最新日记。

下一个分类Database

首页归档页可以看到最新的日记和所有日记。