web-dev-qa-db-fra.com

Flock Linux, comment "simplement" verrouiller un fichier?

Dans Bash, j'essaie de créer une fonction getLock à utiliser avec différents noms de verrous.

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

Mais le troupeau dit flock: bad number: myfilelock

Comment puis-je simplement verrouiller un fichier et le libérer quand je veux, sans avoir à exécuter une commande dans le troupeau?

Il doit être utilisé comme ceci:

getLock myfilelock LOCK_EX
somecommands
........
getLock myfilelock LOCK_UN
16
JorgeeFG

Pour verrouiller le fichier:

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

Pour déverrouiller:

exec 3>&-       # close the file handle

Vous pouvez également le faire comme le décrit la page de manuel flock:

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

... auquel cas le fichier se ferme automatiquement à la sortie du bloc. (Un sous-shell peut également être utilisé ici, en utilisant ( ) plutôt que { }, mais cela devrait être une décision délibérée - car les sous-coquilles ont une dégradation des performances et des modifications de variables d'étendue et d'autres changements d'état).


Si vous utilisez une nouvelle version de bash, vous n'avez pas besoin de gérer manuellement les numéros de descripteurs de fichiers:

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

... maintenant, pour votre fonction, nous allons avoir besoin de tableaux associatifs et d'allocation FD automatique (et, pour permettre au même fichier d'être verrouillé et déverrouillé à partir de chemins différents, GNU readlink) - donc cela ne fonctionnera pas avec les anciennes versions de bash:

declare -A lock_fds=()                        # store FDs in an associative array
getLock() {
  local file=$(readlink -f "$1")              # declare locals; canonicalize name
  local op=$2
  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
}

Si vous êtes sur une plateforme où GNU readlink n'est pas disponible, je vous suggère de remplacer le readlink -f appeler avec realpath de sh-realpath par Michael Kropat (en se basant uniquement sur la fonctionnalité de lien de lecture largement disponible, pas GNU).

35
Charles Duffy