是否可以创建脚本来保存和恢复权限?

Posted

技术标签:

【中文标题】是否可以创建脚本来保存和恢复权限?【英文标题】:Is it possible to create a script to save and restore permissions? 【发布时间】:2011-03-27 21:18:03 【问题描述】:

我使用的是 linux 系统,需要对一组嵌套文件和目录进行一些权限试验。我想知道是否有某种方法可以保存文件和目录的权限,而不保存文件本身。

换句话说,我想保存权限,编辑一些文件,调整一些权限,然后将权限恢复到目录结构,保留更改的文件。

这有意义吗?

【问题讨论】:

【参考方案1】:

最简单的方法是使用 ACL 工具,即使您实际上不使用 ACL。只需调用getfacl -R . >saved-permissions 来备份目录树的权限,调用setfacl --restore=saved-permissions 来恢复它们。

否则,备份权限的方法是使用find -printf。 (GNU find 是必需的,但这就是您在 Linux 上所拥有的。)

find -depth -printf '%m:%u:%g:%p\0' >saved-permissions

你得到一个文件,其中包含由空字符分隔的记录;每条记录包含一个文件的数字权限、用户名、组名和文件名。要恢复,循环记录并调用chmodchownfind-depth 选项是为了以防你想让某些目录不可写(你必须先处理它们的内容)。

您可以使用此 bash sn-p 恢复权限,该 bash sn-p 源自 Daniel Alder 贡献的 sn-p:

while IFS=: read -r -d '' mod user group file; do
  chown -- "$user:$group" "$file"
  chmod "$mod" "$file"
done <saved-permissions

您可以使用以下 awk 脚本将 find 输出转换为一些 shell 代码以恢复权限。

find -depth -printf '%m:%u:%g:%p\0' |
awk -v RS='\0' -F: '
BEGIN 
    print "#!/bin/sh";
    print "set -e";
    q = "\047";


    gsub(q, q q "\\" q);
    f = $0;
    sub(/^[^:]*:[^:]*:[^:]*:/, "", f);
    print "chown --", q $2 ":" $3 q, q f q;
    print "chmod", $1, q f q;
' > restore-permissions.sh

【讨论】:

小修正getfacl命令应该是:getfacl -R。 >保存的权限 这是解决方案的第二部分:恢复文件:while IFS=: read -r -d $'\0' mod user group file; do [ -e "$file" ] || continue;chmod -c "$mod" "$file";chown -Pc "$user" "$file";chgrp -Pc "$group" "$file";done &lt;saved-permissions 最新的解决方案似乎坏了,因为它只是设法在此处处理.* 文件。我不打扰调试,因为基于 ACL 的方法工作得很好。只是标记.... @DanielAlder 我相信交换'chmod'和'chown'语句会更好,这样'chown'首先出现。这样,如果权限包括 SUID 和/或 SGID(例如,6755 而不仅仅是 755),则不会由 chown 重置。【参考方案2】:

先安装ACL包:

sudo apt-get install acl

递归地存储权限和所有权到文件:

getfacl -R yourDirectory > permissions.acl

恢复(相对于当前路径):

setfacl --restore=permissions.acl

【讨论】:

【参考方案3】:

嗯。所以你需要 1)读取文件权限 2)以某种方式存储它们,与每个文件相关联 3)读取您存储的权限并将其设置回来

不是一个完整的解决方案,而是一些想法:

stat -c%a filename
>644

可能结合

find -exec

为了存储这些信息,this so question 有一些有趣的想法。基本上,您创建一个与实际文件匹配的临时文件结构,每个临时文件都包含文件权限

重置您迭代临时文件、读取权限并将实际文件改回。

【讨论】:

我需要stat -f%p,FWIW【参考方案4】:

还有一个特殊的工具叫做metastore:

metastore 是一种工具,用于将文件树中的文件/目录/链接的元数据存储到单独的文件中,然后比较存储的元数据并将其应用于所述文件树。我编写该工具作为 git 的补充,它不存储所有元数据,使其不适合例如将 /etc 存储在存储库中。如果您想创建文件树的 tarball 并确保“所有内容”(例如 xattrs、mtime、所有者、组)与文件一起存储,metastore 也可能会有所帮助。

也可以使用Debian package。

【讨论】:

metastore 已失效的 Git 存储库已镜像到 GitHub 上 github.com/przemoc/metastore【参考方案5】:

保存: find . -type f |xargs ls -la| awk 'print "chmod "$1" "$NF'&gt;./filesPermissions.sh

恢复:sh ./filesPermissions.sh

【讨论】:

为什么这个答案不是最好的?【参考方案6】:

我在https://github.com/robertknight/mandrawer/blob/master/save-file-attrs.py 有一个用于执行此操作的 Python 脚本

save-file-attrs.py save

将当前工作目录根目录树中文件的权限、模式和修改时间保存到本地文件(.saved-file-attrs),并且:

save-file-attrs.py restore

将从文件中恢复这些属性并显示更改。

【讨论】:

【参考方案7】:

你可以通过

获取文件的权限
ls -l | awk 'print $1" "$NF'

这将返回文件名及其权限列表。 将其保存在某处,完成后 - 恢复 (chmod) 每个文件的权限。

【讨论】:

【参考方案8】:

我发现 Dmytro L 的答案非常酷。但是,不幸的是,它不起作用,因为它会生成如下条目:

chmod -rw-r--r-- ./.bashrc

为了避免这种情况,我使用以下命令:

find . -type f | xargs stat -c "%a %n" | awk 'print "chmod "$1" "$2' > ./filesPermissions.sh

基本上,它的作用相同,但会生成八进制条目,例如:

chmod 644 ./.bashrc

哪个有效。

【讨论】:

可能需要引用/转义文件名,否则会错误处理带有空格的名称【参考方案9】:

这是一个使用单个文件轻松执行此操作的示例。不需要额外的工具、脚本、临时文件等。如果需要,您可以扩展此方法以处理更多文件。

在此特定示例中,权限通过stat 命令保存在变量中。然后,该文件被暂时剥夺任何限制性权限。接下来,用它完成一些事情(由于之前的限制,这可能会失败)。终于恢复了原来的权限。

file=$1
saved_permissions=$(sudo stat -c %a $file)
sudo chmod 777 $file
# <DO SOMETHING HERE>
sudo chmod $saved_permissions $file 

【讨论】:

【参考方案10】:

我修改了 Anton 的命令以获取附加字符串 chown user:group /file_or_folder_path。现在您可以获得一个 bash 脚本,其中每个文件/文件夹包含两个字符串。

命令:

find . -type f | xargs stat -c "%a %U:%G %n" | awk 'print "chown "$2" "$3"\nchmod "$1" "$3' > ./filesPermissions.sh

输出示例:

chown root:root /file_or_folder_path
chmod 777 /file_or_folder_path

【讨论】:

【参考方案11】:
#!/bin/bash

if [ $# -ne 1 ]; then
        echo "Enter directory";
        exit 0;
fi
# dump acls
cd $1
>acl
echo "#!/bin/bash">recovery_acl.sh
echo "cd $1">>recovery_acl.sh
f='./'
# create acl file sorted by dir_level
for i in `seq 0 15`;do
  find . -mindepth $i -maxdepth $i -type d -exec getfacl  +|grep -E '*UTS|file:'>>acl
done
sed -i 's/default\:user/\-dm\ u/g' acl
sed -i 's/default\:group/\-dm\ g/g' acl
sed -i 's/user\:/\-m\ u\:/g' acl
sed -i 's/group\:/\-m\ g\:/g' acl
sed -i 's/\#\ file\:\ /\.\//g' acl
sed -i '/^#/d' acl

while IFS='' read -r line ; do
  # grep dir name
  if echo "$line" | grep -q "$f" ; then
    dir="$line"
    continue
  fi
  echo setfacl $line '"'$dir'"'>>recovery_acl.sh
  # grep non def acl (for files)
  if echo "$line" | grep -q '\-m' ; then
    echo setfacl $line '"'$dir'"'/*>>recovery_acl.sh
  fi
done < "acl"
rm -f acl
sed -i 's/134/\\/g' recovery_acl.sh
sed -i 's/040/\ /g' recovery_acl.sh

脚本执行后,将创建另一个“recovery_acl.sh”。 替换您域上的 UTS。 像“没有这样的文件或目录”这样的错误意味着目录是空的。

【讨论】:

【参考方案12】:

我找到了最好的方法(对我来说)用 python 做到这一点!

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import json
import sys
import re
try:
    import posix1e
except ImportError:
    print("No module named 'posix1e'")
    print("You need do: apt install python3-pylibacl")
    sys.exit()

def dump_acl(dir):
    acl_dict = 
    for root, dirs, files in os.walk(dir):
        try:
            path = root.split(os.sep)
            root_acl = str(posix1e.ACL(file=root))
            root_def_acl = str(posix1e.ACL(filedef=root))
            #print(root_acl)
            acl_dict[root] = root_acl
            acl_dict["default_" + root] = root_def_acl
            for file_name in files:
                try:
                    if 'acl.json' in file_name:
                        continue
                    file_path = root + "/" + file_name
                    file_acl = str(posix1e.ACL(file=file_path))
                    acl_dict[file_path] = file_acl
                    #print(file_path)
                except Exception as e:
                    print(e)
                    print(root, '/' + file_name)
                    continue
        except Exception as e:
            print(e)
            print(root, '/' + file_name)
            continue

    with open(dir + '/acl.json', 'bw') as f:
        f.write(json.dumps(acl_dict, ensure_ascii=False).encode('utf8'))
    return


def recovery_acl(dir):
    with open(dir + '/acl.json', 'r') as f:
        acl_dict = json.load(f)
    try:
        for file_path, file_acl in acl_dict.items():
            if file_path.startswith('default_'):
                file_path = file_path.replace('default_', '', 1)
                posix1e.ACL(text = file_acl).applyto(file_path, posix1e.ACL_TYPE_DEFAULT)
                continue
            if 'acl.json' in file_path:
                continue
            file_acl = file_acl.replace('\n', ',', file_acl.count('\n') -1)
            file_acl = file_acl.replace('\134', u'\ ' [:-1])
            file_acl = file_acl.replace('\040', u' ')
            if 'effective' in file_acl:
                file_acl = file_acl.replace('\t', '')
                f_acl = re.sub('#effective:[r,w,x,-]3', '', file_acl)
            posix1e.ACL(text = file_acl).applyto(file_path)
    except Exception as e:
        print(e, file_path, file_acl)
    return

def help_usage():
    print("Usage:")
    print("For dump acl:   ", sys.argv[0], "-d /path/to/dir")
    print("For restore acl:", sys.argv[0], "-r /path/to/dir")
    print("File with acls (acl.json) storing in the same dir")
    sys.exit()


if len(sys.argv) == 3 and os.path.isdir(sys.argv[2]):
    if sys.argv[1] == '-d':
        dump_acl(sys.argv[2])
    elif sys.argv[1] == '-r':
        if os.path.exists(sys.argv[2] + '/acl.json'):
            recovery_acl(sys.argv[2])
        else:
            print("File not found:", sys.argv[2] + '/acl.json')
else:
    help_usage()

备份acl:dump_acl.py -d /path/to/dir

恢复acl:dump_acl.py -r /path/to/dir

执行后,脚本在同一个目录下创建acl.json(witch backup/restore acls)

【讨论】:

【参考方案13】:

我从roaima's post借用这个答案。 我认为这应该是最好的答案:保存权限

find * -depth -exec stat --format '%a %u %g %n'  + >/tmp/save-the-list

恢复权限

while read PERMS OWNER GROUP FILE
do
    chmod "$PERMS" "$FILE"
    chown "$OWNER:$GROUP" "$FILE"
done </tmp/save-the-list

【讨论】:

以上是关于是否可以创建脚本来保存和恢复权限?的主要内容,如果未能解决你的问题,请参考以下文章

基于catalog 创建RMAN存储脚本

linux文件权限误修改之后如何恢复

Vertica备份恢复

求Bash Shell脚本,判定文件是不是存在。

mysql数据库的备份与数据恢复

如何从现有的 MySQL 数据库生成创建用户脚本?