Linux flock, как" просто " заблокировать файл?

в Bash я пытаюсь сделать функцию getLock для использования с разными именами блокировки.

function getLock
{
    getLock_FILE=""
    getLock_OP=""
    case "${getLock_OP}" in
        "LOCK_UN")
            flock -u "${getLock_FILE}"
            rm -fr "${getLock_FILE}"
            ;;
        "LOCK_EX")
            flock -x "${getLock_FILE}"
    esac
}

но стадо говорит flock: bad number: myfilelock

как я могу просто заблокировать файл и выпустить его, когда захочу, без необходимости выполнять команду в стае?

он должен использоваться следующим образом:

getLock myfilelock LOCK_EX
somecommands
........
getLock myfilelock LOCK_UN

1 ответов


заблокировать файл:

exec 3>filename # open a file handle; this part will always succeed
flock -x 3      # lock the file handle; this part will block

чтобы отпустить замок:

exec 3>&-       # close the file handle

вы также можете сделать это так, как описывает страница flock man:

{
  flock -x 3
  ...other stuff here...
} 3>filename

...в этом случае файл автоматически закрывается при выходе из блока. (Подсеть также может использоваться здесь, используя ( ), а не { }, но это должно быть преднамеренное решение - так как подсхемы имеют штраф за производительность, а изменения переменных области и другие изменения состояния сами.)


если вы используете достаточно новую версию bash, вам не нужно вручную управлять номерами дескрипторов файлов:

# this requires a very new bash -- 4.2 or so.
exec {lock_fd}>filename
flock -x "$lock_fd"
exec $lock_fd>&-

...теперь для вашей функции нам понадобятся ассоциативные массивы и автоматическое выделение FD (и, чтобы один и тот же файл был заблокирован и разблокирован из разных путей, GNU readlink) - так что это не будет работать со старыми выпусками bash:

declare -A lock_fds=()                        # store FDs in an associative array
getLock() {
  local file=$(readlink -f "")              # declare locals; canonicalize name
  local op=
  case $op in
    LOCK_UN)
      [[ ${lock_fds[$file]} ]] || return      # if not locked, do nothing
      exec ${lock_fds[$file]}>&-              # close the FD, releasing the lock
      unset lock_fds[$file]                   # ...and clear the map entry.
      ;;
    LOCK_EX)
      [[ ${lock_fds[$file]} ]] && return      # if already locked, do nothing
      local new_lock_fd                       # don't leak this variable
      exec {new_lock_fd}>"$file"              # open the file...
      flock -x "$new_lock_fd"                 # ...lock the fd...
      lock_fds[$file]=$new_lock_fd            # ...and store the locked FD.
      ;;
  esac
}

если вы находитесь на платформе, где GNU readlink недоступно, я бы предложил заменить readlink -f вызов с realpath С sh-realpath Майкла Кропата (полагаясь только на широко доступные функции readlink, а не на расширения GNU).