广告
返回顶部
首页 > 资讯 > 操作系统 >linux中shell如何实现文件锁
  • 334
分享到

linux中shell如何实现文件锁

2023-06-09 16:06:54 334人浏览 泡泡鱼
摘要

这篇文章给大家分享的是有关linux中shell如何实现文件锁的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1. util-linux 的 flock这个命令有两种用法:  flock LOCKFILE

这篇文章给大家分享的是有关linuxshell如何实现文件的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

1. util-linux 的 flock

这个命令有两种用法:  flock LOCKFILE COMMAND  ( flock -s 200; COMMAND; ) 200>LOCKFILEflock 需要保持打开锁文件,对于第二种使用方式并不方便,而且 -s 方式指定文件句柄可能冲突。好处是不需要显式的解锁,进程退出后锁必然释放。

2. liblockfile1 的 dotlockfile

号称最灵活可靠的文件锁实现。其等待时间跟  -r 指定的重试次数有关,重试时间为 sum(5, 10, ..., min(5*n, 60), ...).锁文件不需要保持打开, 带来的问题是需要用 trap EXIT 确保进程退出时删除锁文件.

3. procmail 的 lockfile

跟 dotlockfile 类似, 但可以一次性创建多个锁文件.
在SHELL中实现文件锁,有两种简单的方式。

一是利用普通文件,在脚本启动时检查特定文件是否存在,如果存在,则等待一段时间后继续检查,直到文件不存时创建该文件,在脚本结束时删除文件。为确保脚本在异常退出时文件仍然能被删除,可以借助于trap "cmd" EXIT TERM INT命令。一般这类文件存放在/var/lock/目录下,操作系统在启动时会对该目录做清理。
另一种方法是是使用flock命令。使用方式如下,这个命令的好处是等待动作在flock命令中完成,无需另外添加代码。
( flock 300 ...cmd... flock -u 300 ) > /tmp/file.lock
但flock有个缺陷是,在打开flock之后fork(),子进程也会拥有锁,如果在flock其间有运行daemon的话,必需确保daemon在启动时已经关闭了所有的文件句柄,不然该文件会因为daemon一直将其置于打开状态而无法解锁。

一个实现linux shell文件锁的例子
最近看到很多讨论如何能不让脚本重复执行的问题,实际就是文件锁的概念,写了一个小例子:
把这个作为文件开头不会产生重复执行的情况。(我想两个执行脚本的文件名一模一样应该不会经常出现吧)

#!/bin/bashLockFile(){ find/dev/shm}]&&exit ln -s /proc/$$/dev/shm/${0##*/} trap "Exit" 0 1 2 3 15 22 24}Exit(){ unlink /dev/shm/${0##*/}; exit 0;}LockFile# main program# program ......#Exit

/var/lock/subsys目录的作用的说明
很多程序需要判断是否当前已经有一个实例在运行,这个目录就是让程序判断是否有实例运行的标志,比如说xinetd,如果存在这个文件,表示已经有xinetd在运行了,否则就是没有,当然程序里面还要有相应的判断措施来真正确定是否有实例在运行。
通常与该目录配套的还有/var/run目录,用来存放对应实例的PID,如果你写脚本的话,会发现这2个目录结合起来可以很方便的判断出许多服务是否在运行,运行的相关信息等等。
   实际上,判断是否上锁就是判断这个文件,所以文件存在与否也就隐含了是否上锁。而这个目录的内容并不能表示一定上锁了,因为很多服务在启动脚本里用touch来创建这个加锁文件,在系统结束时该脚本负责清除锁,这本身就不可靠(比如意外失败导致锁文件仍然存在),我在脚本里一般是结合PID文件(如果有PID文件的话),从PID文件里得到该实例的PID,然后用ps测试是否存在该PID,从而判断是否真正有这个实例在运行,更加稳妥的方法是用进程通讯了,不过这样的话单单靠脚本就做不到了。
flock命令在我的系统属于util-linux-2.13-0.46.fc6包,如果没有此命令,尝试更新您系统下的util-linux包。
介绍此命令的原因:
论坛中曾有woodie兄写的脚本串行化的讨论,已经很完善了。
但flock此命令既与shell脚本结合的很好,而且与C/PERL/PHP等语言的flock函数用法很相似,使用起来也很简单。相比之下,woodie兄那篇的内容需要不浅的shell功底来理解。
两种格式分别为:
       flock [-sxon] [-w timeout] lockfile [-c] command...

       flock [-sxun] [-w timeout] fd
介绍一下参数:
-s为共享锁,在定向为某文件的FD上设置共享锁而未释放锁的时间内,其他进程试图在定向为此文件的FD上设置独占锁的请求失败,而其他进程试图在定向为此文件的FD上设置共享锁的请求会成功。
-e为独占或排他锁,在定向为某文件的FD上设置独占锁而未释放锁的时间内,其他进程试图在定向为此文件的FD上设置共享锁或独占锁都会失败。只要未设置-s参数,此参数默认被设置。
-u手动解锁,一般情况不必须,当FD关闭时,系统会自动解锁,此参数用于脚本命令一部分需要异步执行,一部分可以同步执行的情况。
-n为非阻塞模式,当试图设置锁失败,采用非阻塞模式,直接返回1,并继续执行下面语句。
-w设置阻塞超时,当超过设置的秒数,就跳出阻塞,返回1,并继续执行下面语句。
-o必须是使用第一种格式时才可用,表示当执行command前关闭设置锁的FD,以使command的子进程不保持锁。
-c执行其后的comand。
举个实用的例子:

#!/bin/bash{flock -n 3[ $? -eq 1 ] && { echo fail; exit; }echo $$sleep 10} 3<>mylockfile

此例的功能为当有一个脚本实例正在执行时,另一个试图执行该脚本的进程会失败退出。
sleep那句可以换成您需要执行的语句段。
这里请注意一点,我使用<>打开mylockfile,原因是定向文件描述符是先于命令执行的。因此假如在您要执行的语句段中需要读写mylockfile文件,例如想获得上一个脚本实例的pid,并将此次的脚本实例的pid写入mylockfile。此时直接用>打开mylockfile会清空上次存入的内容,而用<打开mylockfile当它不存在时会导致一个错误。当然这些问题都可以用其他方法解决,我只是点出这种最通用的方法。

【背景介绍】

CU上曾经有几个帖子讨论到一个实际问题,就是如何限制同一时刻只允许一个脚本实例运行。其中本版新老斑竹和其它网友都参加了讨论,但以faintblue兄的帖子对大家启发最大,下面的背景介绍中许多内容都是来自于他。在此感谢faintblue兄,也感谢斑竹和其它朋友!
woodie总结了一下现有的结果,大体上可以分为两种思路:
一、简单的方法是,用ps一类命令找出已经运行脚本的数量,如果大于等于2(别忘了把自己也算进去^_^),就退出当前脚本,等于1,则运行。这种方法简单是简单,不过有一些问题:
首先,ps取得脚本文件进程数量就有很多陷阱,例如有时无法ps到脚本文件的名称;
即使可以ps到脚本名,如果用到管道的话,由于子shell的原因,在大多数平台下会得到奇怪的结果,有时得到数字a,有时又得到数字b,让人无所适从;
就算计数的问题已经解决了,还有问题,不过不太严重:如果两个脚本实例同时计数,显然数字都应该等于2,于是两个都退出了。于是在这一时间点上没有一个脚本在执行;

二、加锁的方法。就是脚本在执行开始先试图得到一个“锁”,得到则继续执行,反之就退出。
加锁方法也存在一些问题,主要集中在两个方面:
其一,加锁时如何避免竞态条件(race condition)。即如何找到一些“原子”操作,使得加锁的动作一步完成,中间不能被打断。否则就可能出现下面的情况:
脚本1检测到没有锁被占用;
然后脚本2也检测到没有锁被占用;
脚本1加锁,开始执行;
然后脚本2(错误地)加锁,也开始执行;
看到吗,两个脚本在同时执行。:(
可能的一些加锁的“原子”操作有:
1.创建目录,当一个进程创建成功后其它进程都会失败;
2.符号链接:ln -s,一个链接创建后其它进程的ln -s命令会出错;
3.文件首行的竞争,多个进程以append的方式同时写到文件,只有惟一一个进程写到了文件的第一行,因为不可能有两个第一行。^_^
4.其它软件包的加锁工具,通常是C语言二进制程序,自己写的也行。
目前加锁时的问题已经可以解决。
其二,找到一种方法避免出现“死锁”的情况,这里是指:虽然“锁”被占用,但却没有脚本在执行。这通常在脚本意外退出,来不及释放占用的“锁”之后。如收到一些系统信号后退出,机器意外掉电后退出等。
对于前者的情况,可以用trap捕获一些信号,在退出前释放锁;但有些信号是无法捕获的。
对于后者,可以在机器重起后用脚本自动删除锁来解决。不过有点麻烦。
所以比较理想的是脚本自己来检测死锁,然后释放它。不过问题的难点在于如何找到一种“原子”操作,将检测死锁和删除死锁的动作一步完成,否则又会出现与加锁时同样的竞态条件的问题。例如:
进程1检测到死锁;
进程2监测到死锁;
进程1删除死锁;
进程x(也可能是进程1自己)加锁,开始运行;
进程2(错误地)删除死锁;
此时锁没有占用,于是任意进程都可以加锁并投入运行。
这样又出现了两个进程同时运行的情况。:(
可惜的是:在迄今为止的讨论之后,woodie还没有找到一种合适的“原子”操作。:(只是找到了一种稍微好些的办法:就是在删除时用文件的inode作标识,于是其它进程新建的锁(文件名虽然相同,但inode相同的机率比较微小)不容易被意外删除。这个方法已经接近完美了,可惜还是存在误删的微小几率,不能说是100%安全。唉,山重水复疑无路啊!:(

最近又有网友问起这个问题,促使我又再次思考。从我以前的一个想法发展了一下,换了一种思路,便有豁然开朗的感觉。不敢藏私,写出来请大家debug。^_^

基本的想法就是:借鉴多进程编程中临界区的概念,如果各个进程进入我们设立的临界区,只可能一个一个地顺序进入,不就能保证每次只有一个脚本运行了吗?怎样建立这样一种临界区呢?我想到了一种方法,就是用管道,多个进程写到同一个管道,只可能一行一行地进入,相应的,另一端也是一行一行地读出,如此就可以实现并行执行的多个进程进入临界区时的“串行化”。这与faintblue兄以前贴出的append文件的方法也是异曲同工。
我们可以让并行的进程同时向一个管道写一行请求,内容是其进程号,在管道另一端顺序读取这些请求,但只有第一个请求会得到一个“令牌”,被允许开始运行;后续的请求将被忽略,对应的进程没有得到令牌,就自己退出。这样就保证了任意时间只有一个进程运行(严格地说是进入临界区)。说到“令牌”,熟悉网络发展史的朋友可能会联想到IBM的Token Ring架构,每一时刻只能有一个主机得到令牌并发送数据,没有以太网的“碰撞”问题。可惜如同微通道技术一样,IBM的技术是不错,但最终还是被淘汰了。不错,这里令牌的概念就是借用于Token Ring。^_^
当一个进程执行完毕,向管道发送一个终止信号,即交回“令牌”,另一端接受到后,又开始选取下一个进程发放“令牌”。
您可能会问了,那么死锁问题又如何解决呢?别急,我在以前的讨论中曾提出将检测处理死锁的代码单独拿出来,交给一个专门的进程来处理的想法,这里就具体实践这样一种思路。当检测和删除死锁的任务由一个专门的进程来执行时,就没有多个并发进程对同一个锁进行操作,所以竞态条件发生的物质基础也就根本不存在了。^_^
再发展一下这个思路,允许同时执行多个进程如何?当然可以!只要设立一个计数器,达到限制的数字就停止发放“令牌”即可。
下面就是woodie上述思路的一个实现,只是在Centos 4.2下简单地测试了一下,可能还有不少错误,请大家帮忙“除虫”。^_^思路上有什么问题也请不吝指教:
脚本1,token.sh,负责令牌管理和死锁检测处理。与下一个脚本一样,为了保持脚本的最大的兼容性,尽量使用Bourne shell的语法,并用printf代替了echo,sed的用法也尽量保持通用性。这里是由一个命名管道接受请求,令牌在一个文件中发出。如果用ksh也许可以用协进程来实现,熟悉ksh的朋友可以试一试。^_^

#!/bin/sh #name: token.sh #function: serialized token distribution, at anytime, only a cerntern number of token given out #usage: token.sh [number] & #number is set to allow number of scripts to run at same time #if no number is given, default value is 1 if [ -p /tmp/p-aquire ]; then  rm -f /tmp/p-aquire fi if mkfifo /tmp/p-aquire; then  printf "pipe file /tmp/p-aquire created\n" >>token.log else  printf "cannot create pipe file /tmp/p-aquire\n" >>token.log  exit 1 fi loop_times_before_check=100 if [ -n "$1" ];then  limit=$1 else  # default concurrence is 1  limit=1 fi number_of_running=0 counter=0 while :;do  #check stale token, which owner is died unexpected  if [ "$counter" -eq "$loop_times_before_check" ]; then   counter=0   for pid in `cat token_file`;do    pgrep $pid    if [ $? -ne 0 ]; then     #remove lock       printf "s/ $pid//\nwq\n"|ed -s token_file       number_of_running=`expr $number_of_running - 1`    fi   done  fi  counter=`expr $counter + 1`  #  if [ "$number_of_running" -ge "$limit" ];then   # token is all given out. bypass all request until a instance to give one back   pid=`sed -n '/stop/ {s/\([0-9]\+\) \+stop/\1/p;q}' /tmp/p-aquire`   if [ -n "$pid" ]; then    # get a token returned    printf "s/ $pid//\nwq\n"|ed -s token_file    number_of_running=`expr $number_of_running - 1`    continue   fi  else   # there is still some token to give out. serve another request   read pid action < /tmp/p-aquire     if [ "$action" = stop ]; then      # one token is given back.      printf "s/ $pid//\nwq\n"|ed -s token_file      number_of_running=`expr $number_of_running - 1`     else      # it's a request, give off a token to instance identified by $pid      printf " $pid" >> token_file      number_of_running=`expr $number_of_running + 1`     fi  fi done

--------------------------------------------------------------------------------------------
修订记录:
1.修正token.sh的一个BUG,将原来用sed删除失效令牌的命令用ed命令代替。感谢r2007和waker两位指出错误!
--------------------------------------------------------------------------------------------

脚本2:并发执行的脚本 -- my-script。在"your code Goes here"一行后插入你自己的代码,现有的是我用来测试的。

#!/bin/sh # second to wait that the ditributer gives off a token a_while=1 if [ ! -p /tmp/p-aquire ]; then  printf "cannot find file /tmp/p-aquire\n" >&2  exit 1 fi # try to aquire a token printf "$$\n" >> /tmp/p-aquire sleep $a_while # see if we get one grep "$$" token_file if [ $? -ne 0 ]; then  # bad luck. :(  printf "no token free now, exitting...\n" >&2  exit 2 fi

这个脚本是将文件锁得,不过我对这脚本还有一些疑惑的地方,暂且不讨论,等以后回头再来谈

#!/bin/sh# filelock - A flexible file locking mechanism.retries="10"      # default number of retriesaction="lock"      # default actionnullcmd="/bin/true"   # null command for lockfilewhile getopts "lur:" opt; do case $opt in  l ) action="lock"   ;;  u ) action="unlock"  ;;  r ) retries="$OPTARG" ;; esacdoneshift $(($OPTIND - 1))if [ $# -eq 0 ] ; then cat << EOF >&2Usage: $0 [-l|-u] [-r retries] lockfilenameWhere -l requests a lock (the default), -u requests an unlock, -r Xspecifies a maximum number of retries before it fails (default = $retries).EOF exit 1fi# Ascertain whether we have lockf or lockfile system appsif [ -z "$(which lockfile | grep -v '^no ')" ] ; then echo "$0 failed: 'lockfile' utility not found in PATH." >&2 exit 1fiif [ "$action" = "lock" ] ; then if ! lockfile -1 -r $retries "$1" 2> /dev/null; then  echo "$0: Failed: Couldn't create lockfile in time" >&2  exit 1 fielse  # action = unlock if [ ! -f "$1" ] ; then  echo "$0: Warning: lockfile $1 doesn't exist to unlock" >&2  exit 1 fi rm -f "$1"fiexit 0

感谢各位的阅读!关于“linux中shell如何实现文件锁”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

--结束END--

本文标题: linux中shell如何实现文件锁

本文链接: https://www.lsjlt.com/news/256960.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • linux中shell如何实现文件锁
    这篇文章给大家分享的是有关linux中shell如何实现文件锁的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1. util-linux 的 flock这个命令有两种用法:  flock LOCKFILE...
    99+
    2023-06-09
  • shell中怎么实现文件锁功能
    今天就跟大家聊聊有关shell中怎么实现文件锁功能,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。关于flockflock 是对于整个文件的建议性锁。也就是说,如果一个进程在一个文件(...
    99+
    2023-06-09
  • shell脚本实现文件锁功能
    1.背景 当多个进程可能会对同样的数据执行操作时,这些进程需要保证其它进程没有在操作,以免损坏数据。通常,这样的进程会使用一个“锁文件”,也就是建立一个文件来告诉别的进程自己在运行,如果检测到那个文件存在...
    99+
    2022-06-04
    脚本 功能 文件
  • golang如何实现文件锁
    本篇内容主要讲解“golang如何实现文件锁”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“golang如何实现文件锁”吧!在golang中,可以利用sync包的api来实现文件锁。文件锁(flo...
    99+
    2023-07-04
  • Linux中shell怎么实现压缩多个文件
    这篇文章主要介绍Linux中shell怎么实现压缩多个文件,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Linux环境下写一个脚本从键盘让用户输入几个文件,脚本能够将此几个文件归档压缩成一个文件:首先介绍一下case...
    99+
    2023-06-09
  • shell中如何实现插入文本到文件
    小编给大家分享一下shell中如何实现插入文本到文件,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!首先,打开你的 Terminal。改写文件如果你刚刚创建了一个文...
    99+
    2023-06-09
  • linux文件带锁如何删除
    如果你想要删除一个带有锁的 Linux 文件,可以使用以下方法之一:1. 使用 rm 命令强制删除文件。在终端中输入以下命令: &n...
    99+
    2023-08-30
    linux
  • Linux中怎么实现makefile 和shell文件相互调用
    Linux中怎么实现makefile 和shell文件相互调用,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。shell 文件内调用makefile文件:#!/bin/bashc...
    99+
    2023-06-09
  • Linux shell实现压缩多个文件代码实例
    Linux环境下写一个脚本 从键盘让用户输入几个文件,脚本能够将此几个文件归档压缩成一个文件: 1.首先介绍一下case语句格式 2.脚本如下: DEST读取的是压缩后文件的名称,COMP读取的是压缩的方式 给文件...
    99+
    2022-06-03
    Linux shell 压缩 文件
  • linux如何锁定一个文件夹
    这篇文章主要为大家展示了“linux如何锁定一个文件夹”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“linux如何锁定一个文件夹”这篇文章吧。锁定一个文件夹为了我的数据隐私,我想要锁定我文件服务...
    99+
    2023-06-27
  • 如何用shell脚本实现linux系统文件完整性检测
    这篇文章主要介绍“如何用shell脚本实现linux系统文件完整性检测”,在日常操作中,相信很多人在如何用shell脚本实现linux系统文件完整性检测问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何用sh...
    99+
    2023-06-09
  • Linux中shell ftp命令如何根据文件日期下载文件
    这篇文章主要介绍Linux中shell ftp命令如何根据文件日期下载文件,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!需求:ftp获取远程数据的文件,根据文件的创建时间点下载文件。 可以自行扩展根据文件的大小等其他...
    99+
    2023-06-09
  • Linux下文件剪切的shell脚本实现代码
    需求描述 编写shell脚本实现Linux下不同目录(路径)之间的文件的剪切(移动)操作。 其中,文件移动之前所在的目录称为源目录,文件移动之后所在的目录称为目的目录。要求当源目录不存在、源目录下无文件...
    99+
    2022-06-04
    脚本 代码 文件
  • linux下shell脚本备份文件的方法实现
    目录1、shell自动备份2、关于find命令:1、shell自动备份 主要功能: 1)将pathSrc目录中的文件拷贝到pathDst目录中去。 具体步骤:先查询源目录和目标目录中的文件,分别存在fileSrc和fil...
    99+
    2022-08-22
  • Linux中shell如何实现HTTP服务
    这篇文章给大家分享的是有关Linux中shell如何实现HTTP服务的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、前言使用代理服务器 HAProxy 对 Mysql 做负载均衡是常用方案,为提高可用性,当某个...
    99+
    2023-06-09
  • Linux如何实现文件操作
    这篇文章主要介绍了Linux如何实现文件操作,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。文件是linux中的一个重要概念。在Linux中,一切(几乎一切)都是文件。简单的说...
    99+
    2023-06-28
  • linux如何实现文件管理
    这篇文章将为大家详细讲解有关linux如何实现文件管理 ,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、文件系统及Shell的基本概念 1.文件系统的含义   文件系统是用来管理和组织保存在磁盘驱动器上...
    99+
    2023-06-13
  • linux如何实现文件搜索
    这篇文章主要介绍linux如何实现文件搜索,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1、linux中包含大量的文件,对于文件查找,linux提供了find命令。find是一个非常有效的工具,它可以遍历目标目录甚至...
    99+
    2023-06-09
  • Linux文件执行中的锁定怪现象分析
    这篇文章将为大家详细讲解有关Linux文件执行中的锁定怪现象分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。linux下,一个可执行文件exe1正在执行中,rm &ndash;f可以将其删除,m...
    99+
    2023-06-13
  • shell脚本实现linux系统文件完整性检测
    今天发现个可以检测系统文件完整性的shell脚本,自己试了下还可以吧,介绍给大家。 系统:centos 5.x 脚本内容: cat my_filecheck.sh #!/bin/bash # # 变...
    99+
    2022-06-04
    脚本 完整性 文件
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作