在前面的篇章里面,我们已经介绍了常见的各种shell命令操作。然而,在实际工作中,我们经常会遇到多种任务需要在一定时间内都解决掉。如果这些任务是相互独立的,即不存在先后执行关系,那么我们完全可以让它们同时处理,这样可以大大缩短任务的执行时间,提高我们的工作效率。在其他高级语言中,比如C++或者java,我们通常会采用多线程或者多进程来处理。同样,利用shell脚本我们也能实现多任务并发处理。这一节将介绍如何利用shell脚本进行多任务并发处理。

1.基本原理

关于如何创建多个进程同时运行,在前面的章节我们已有介绍,可以通过协程或者&操作实现。在这里主要讲如何进行控制,即如何按照预期目标让这些多进程有序进行。

要控制创建的进程按照预期目标进行操作,必然涉及到进程间的通信。关于进程间通信的技术有很多,比如临界区、管道、文件、信号、信号量、套接字等等。而对于多进程并发操作,我们将采用管道技术进行控制。

在类Unix操作系统中,管道是一个由标准输入输出链接起来的进程集合,因此,每一个进程的输出将直接作为下一个进程的输入。本质上讲,管道是一种特殊的文件。

管道有一个特点,如果管道中没有数据,那么取管道数据的操作就会滞留,直到管道内进入数据,然后读出后才会终止这一操作;同理,写入管道的操作如果没有读取管道的操作,这一动作就会滞留。

然而与之前介绍的管道命令“|”不同的是,这个管道需要创建者进行命名。为了区分它们,我们把前一种管道称为匿名管道,后一种管道称为命名管道。接下来,我们将详细比较这种管道的异同,以及为什么在多进程并发中需要采用命名管道。

1.1 匿名管道

在类Unix操作系统的命令行中,匿名管道使用ASCII中垂直线“|”作为匿名管道符,匿名管道的两端是两个普通的、匿名的、打开的文件描述符:一个只读端和一个只写端,这就让其它进程无法连接到该匿名管道。

例如:

cat file | cut -b 3

为了执行上面的指令,Shell创建了两个进程来分别执行cat和cut。值得注意的是,两个进程都连接到了管道上,这样写入进程cat就将其标准输出(文件描述符为fd 1)连接到了管道的写入端,读取进程cut就将其标准输入(文件描述符为fd 0)连接到了管道的读入端。实际上,这两个进程并不知道管道的存在,它们只是从标准文件描述符中读取数据和写入数据。shell必须要完成相关的工作。

1.2命名管道

命名管道也称FIFO,是First In First Out的缩写。从语义上来讲,FIFO其实与匿名管道类似,但值得注意:在文件系统中,FIFO拥有名称,并且是以设备特俗文件的形式存在的;

任何进程都可以通过FIFO共享数据;

除非FIFO两端同时有读与写的进程,否则FIFO的数据流通将会阻塞;

匿名管道是由shell自动创建的,存在于内核中;而FIFO则是由程序创建的(比如mkfifo命令),存在于文件系统中;

匿名管道是单向的字节流,而FIFO则是双向的字节流;

1.3多进程并发控制

在有了前面的基础知识之后,我们来讲如何使用命名管道进行多进程并发控制。

命名管道,从它的缩写我们可以看出它具有队列的性质,实际亦然。使用命名管道进行多进程并发控制的基本步骤为:创建一个命令管道

将命名管道绑定到一个特定的文件描述符

设置命名管道的大小。注意命名管道的大小,是通过写入记录的行数来决定的

依次读取命名管道,来创建运行新进程,执行多任务

四个步骤对应四个关键点,因此学习的时候需要牢牢记住。

2.具体实现

由于oracle数据库是目前最好的商用关系型数据库,在实际的工作中我们会经常用到。在关于数据库的操作,我们经常要做的就是数据的导入导出。这里以此为例,介绍如何使用shell多任务并发处理脚本进行oracle数据库的数据导入。

#! /bin/bash

source /etc/profile;

tempfifo=$$.fifo # $$表示当前执行文件的PID

cnt=$1 # 进程数目

data_path=$2 # 数据文件路径

ctl_path=$3 #控制文件路径

db_user=$4 #数据库用户名

db_passwd=$5 #数据库密码

#捕获Ctrl+C中断命令,则关闭文件描述符1000的读写,并正常退出

trap "exec 10>&-;exec 10

#创建一个管道文件,并与文件描述符10绑定

mkfifo $tempfifo

exec 10<>$tempfifo

rm -rf $tempfifo

#对文件描述符10进行写入操作。通过循环写入cnt个空行,这个cnt就是我们要定义的后台并发的线程数。

for ((i=1; i<=$cnt; i++))

do

echo >&10

done

for file in ` ls $data_path `

do

#读取命名管道内容,并创建进程在后台运行

read -u10

{

#导入数据文件到oracle数据库,具体不详细写明,大家可以根据需要结合后面的内容自己实现

obcp $file $db_user $db_passwd $data_path $ctl_path

#写入空行,保持命名管道的容量不变,不然会阻塞

echo >&10

} &

done

#等待子进程都退出,然后关闭文件描述符10再退出

wait

echo "done"

exec 10>&-

exec 10

exit 0

3.oracle数据库的建表与导数相关操作

3.1 oracle数据库的连接

sqlplus user/passwd@ip:port/dbname

3.2 清空已有的表

例如:删除当前用户下的所有表的存储过程

create or replace PROCEDURE pro_dropalltables IS

BEGIN

declare cursor cur_tables is (select table_name from USER_TABLES);

begin

for v_table in cur_tables

loop

DBMS_OUTPUT.PUT_LINE('grant all on ' || v_table.table_name || ' to public ');

execute immediate 'drop table ' || v_table.table_name || ' cascade constraints purge ';

end loop;

end;

END pro_dropalltables ;

3.3 建立建表辅助存储过程

例如:删除表dropifexits.sql

create or replace PROCEDURE pro_dropifexits(p_table in varchar2)

AS

BEGIN

select count(*) into v_count from from USER_TABLES where table_name=upper(p_table ))

IF v_count>0 then

DBMS_OUTPUT.PUT_LINE('drop table' || p_table);

execute immediate 'drop table' || p_table ;

end IF;

END pro_dropifexits;

3.4 建表

exec pro_dropifexits('xxx');

create table tab_xxx(

xx char(10),

...

...

);

partition by list(xxx)

(

partition partiton_xx values('xxxxxx');

);

grant all on tab_xxx to dbuser;

3.5 添加、删除分区

例如:添加分区

create or replace PROCEDURE pro_addpartition(p_centre_id in varchar2,tablespace_var in varchar2,partition_var in varchar2)

AS

BEGIN

declare cursor cur_tables is select table_name from USER_PART_TABLES where table_name in (select table_name from USER_TABLES);

begin

for v_table in cur_tables

loop

DBMS_OUTPUT.PUT_LINE('grant all on ' || v_table.table_name || ' to public ');

execute immediate 'alter table' || v_table.table_name || ' add partition' || partition_var || 'values( ' || p_centre_id || ') tablespace' || tablespace_var ;

end loop;

end;

END pro_addpartition ;

例如:删除分区

create or replace PROCEDURE pro_addpartition(p_centre_id in varchar2,tablespace_var in varchar2,partition_var in varchar2) is v_count number(10);

BEGIN

declare cursor cur_tables is select table_name from USER_PART_TABLES where table_name in (select table_name from USER_TABLES);

begin

for v_table in cur_tables

loop

select count(*) into v_count from user_tab_partitions where TABLE_NAME=v_table.table_name in (select table_name from USER_TABLES)

IF v_count>0 then

DBMS_OUTPUT.PUT_LINE('grant all on ' || v_table.table_name || ' to public ');

execute immediate 'alter table' || v_table.table_name || ' drop partition' || partition_var ;

end IF;

end loop;

end;

END pro_addpartition ;

3.6 授权

例如:PRO_GRANTSCRIPT .sql

create or replace PROCEDURE PRO_GRANTSCRIPT IS

BEGIN

declare cursor cur_tables is (select table_name from USER_TABLES);

begin

for v_table in cur_tables

loop

DBMS_OUTPUT.PUT_LINE('grant all on ' || v_table.table_name || ' to public ');

execute immediate 'grant all on ' || v_table.table_name || ' to public ';

end loop;

end;

END PRO_GRANTSCRIPT ;

3.7 导数

数据格式:以"|!"作为属性分隔符,"!@!"作为元组分隔符

sqlldr命令格式

sqlldr infile='xxx' ctrl='/path/xx.ctrl' bad='/path/xx.bad' log='/path/xx.log' errors=1000

ctrl格式:

LOAD DATA

INFILE '/home/wan/xx.txt' "str X'0A214021'"

INTO TABLE tab_xx

insert(append)

fields terminated by '|!'

trailing nullcols

(

xx char(10),

...

...

)

另一种解决方式是将sqlldr写成一个执行命令,然后将ctrl文件批量化,最后就可以批量执行导数功能。

3.8 exp和imp导出、导入数据库备份

exp信息:

exp user/passwd@ip:port file=xxx/xxx.dmp log=xxx/xxx.log

imp信息:

imp user/passwd@ip:port file=xxx/xxx.dmp log=xxx/xxx.log full=y ignore=y

3.9 使用spool将执行结果写入文件

例如:查找所有的表名

set heading off;

set feedback off;

set trimspool on;

set colsep '|';

set wrap on;

spool /home/wan/file/test.txt

select table_name from USER_TABLES;

spool off;

shell mysql并发_shell脚本中的多进程并发处理相关推荐

  1. shell取mysql字段_shell 脚本中获取mysql多个字段的值

    从mysql中查询出的结果为:mysql -Ne "SELECT ip,port FROM op.host WHERE os='linux' and type='支持'" +--- ...

  2. shell如何解决mysql交互式_shell脚本与mysql交互方法汇总

    有大侠知道其他方法的,还请不吝赐教,在此谢过:) shell脚本导入数据文件到mysql内 当然是利用mysqlimport啦 示例脚本: #!/bin/sh # import test_table. ...

  3. shell脚本中数组的使用_Shell脚本中的数组

    shell脚本中数组的使用 Knowing how to work with arrays in shell scripts will help you work with larger datase ...

  4. python logger设置信息取得_shell 脚本中如何获取 python logging 打印的信息?

    在 shell 脚本中调用 python 的接口,但是 python API 是通过 python 的 logging 把相关信息打印到屏幕上的,不知道这种情况在 shell 中怎么获取这些 logg ...

  5. mysql 备份_shell脚本实现MySQL全量备份+异地备份

    一. 知识储备 1) find命令,参考:Linux find 命令 2) MySQL导出数据库语法: mysqldump -u用户名 -p密码 数据库名 > 数据库名.sql 3) rsync ...

  6. 测试过程中用shell的地方_Shell脚本应用——条件测试操作

    Shell脚本应用--条件测试操作 前言:在简单的shell脚本程序中,各条语句将按先后顺序依次执行,从而实现批处理的自动化过程,这就使得脚本过于机械化,不够"智能",难以处理更加 ...

  7. mysql中的shell脚本命令_shell脚本中mysql命令

    展开全部 本文介绍 MySQL 8.0 shell 子模块 Util 的两个导入特性 importTable/import_table(JS和python 版本的命名差e68a84e8a2ad6261 ...

  8. shell mysql 取值_shell 脚本中获取mysql多个字段的值

    从mysql中查询出的结果为:mysql -Ne "SELECT ip,port FROM op.host WHERE os='linux' and type='支持'" +--- ...

  9. mysql判断不等于空的脚本_Shell脚本中判断输入变量或者参数是否为空的方法

    1.判断变量 复制代码代码如下: read -p "input a word :" word if  [ ! -n "$word" ] ;then echo & ...

最新文章

  1. OpenCV+python:直方图的概念及绘制(Histogram)
  2. 泛型java 代码讲解_Java泛型详解
  3. monkey测试_安卓测试之monkey
  4. SpringSecurity系列(三) Spring Security 表单登录
  5. 判定三角形程序c语言,c语言判定三角形的各种类型——请大家指点
  6. 马克思主义基本原理习题册
  7. 解决刷新页面Vuex数据丢失问题
  8. Ubuntu 下查看图片
  9. esp32查询剩余内存_ESP32 Arduino教程:获取自由堆-esp文件
  10. 如何将鼠标和键盘连接到PlayStation 4
  11. 网站图片定位代码html5,CSS中背景图片的定位
  12. 辰信领创荣获“2016中国IT风云榜”两项大奖
  13. Java开发环境及其特点
  14. 你知道数据分析报告应该如何写吗?
  15. 虚拟机SSH免密登录
  16. ubuntu在目录下文件中搜索关键字
  17. PPT设计:PPT封面页9种设计布局/思维
  18. java 通联支付接口_allinpay 通联支付接口实例
  19. Java 模拟栈结构
  20. 计算机隐藏文件夹无法显示,无法显示隐藏文件怎么办 无法显示隐藏文件夹的解决方法...

热门文章

  1. 常垒·会客厅:医保局时代下的医院智能数据大变革
  2. 音圈电机模组选择直线导轨还是交叉导轨?
  3. android 点击震动,Android 实现为点击事件添加震动效果
  4. 无密码登陆的ssh和ssh-agent
  5. SEO搜索引擎优化(总结学习)
  6. 李嘉诚--理财--如何支配你的金钱
  7. IDEA(或Android Studio)CamelCase插件的使用(解释了CamelCase插件无法使用问题)
  8. 【Python】京东消费行为数据分析可视化实战案例
  9. 水晶报表填充.Net Objects数据源
  10. 智能移动机器人--科研项目汇总