【问题标题】:Perl script for finding unowned files not finding anything用于查找无主文件的 Perl 脚本未找到任何内容
【发布时间】:2014-04-10 09:46:17
【问题描述】:

我编写了一个脚本,旨在查找不属于现有用户或组的所有文件。但是,尽管已经创建了一个测试用户,然后将其删除,留下了 /home 目录,脚本还是找不到它。显然我在脚本的逻辑中有一个错误。我就是找不到。

#!/usr/bin/perl

# Directives which establish our execution environment
use warnings;
use strict;
use File::Find;
no warnings 'File::Find';
no warnings 'uninitialized';

# Variables used throughout the script
my $OUTDIR = "/var/log/tivoli/";
my $MTAB = "/etc/mtab";
my $PERMFILE = "orphan_files.txt";
my $TMPFILE = "orphan_files.tmp";
my $ROOT = "/";
my(@devNum, @uidNums, @gidNums);

# Create an array of the file stats for "/"
my @rootStats = stat("${ROOT}");

# Compile a list of mountpoints that need to be scanned
my @mounts;

open MT, "<${MTAB}" or die "Cannot open ${MTAB}, $!";

# We only want the local HDD mountpoints
while (<MT>) {
  if ($_ =~ /ext[34]/) {
    my @line = split;
    push(@mounts, $line[1]);

  }

}

close MT;

# Build an array of each mountpoint's device number for future comparison
foreach (@mounts) {
  my @stats = stat($_);
  push(@devNum, $stats[0]);
  print $_ . ": " . $stats[0] . "\n";

}

# Build an array of the existing UIDs on the system
while((my($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell)) = getpwent()) {
  push(@uidNums, $uid);

}

# Build an array of existing GIDs on the system
while((my($name, $passwd, $gid, $members)) = getgrent()){
  push(@gidNums, $gid);

}

# Create a regex to compare file device numbers to.
my $devRegex = do {
  chomp @devNum;
  local $" = '|';
  qr/@devNum/;

};


# Create a regex to compare file UIDs to.
my $uidRegex = do {
  chomp @uidNums;
  local $" = '|';
  qr/@uidNums/;

};

# Create a regex to compare file GIDs to.
my $gidRegex = do {
  chomp @gidNums;
  local $" = '|';
  qr/@gidNums/;

};

print $gidRegex . "\n";

# Create the output file path if it doesn't already exist.
mkdir "${OUTDIR}" or die "Cannot execute mkdir on ${OUTDIR}, $!" unless (-d "${OUTDIR}");

# Create our filehandle for writing our findings
open ORPHFILE, ">${OUTDIR}${TMPFILE}" or die "Cannot open ${OUTDIR}${TMPFILE}, $!";

foreach (@mounts) {
  # The anonymous subroutine which is executed by File::Find
  find sub {
    my @fileStats = stat($File::Find::name);

    # Is it in a basic directory, ...
    return if $File::Find::dir =~ /sys|proc|dev/;

    # ...an actual file vs. a link, directory, pipe, etc, ...
    return unless -f;

    # ...local, ...
    return unless $fileStats[0] =~ $devRegex;

    # ...and unowned? If so write it to the output file
    if (($fileStats[4] !~ $uidRegex) || ($fileStats[5] !~ $gidRegex)) {
      print $File::Find::name . " UID: " . $fileStats[4] . "\n";
      print $File::Find::name . " GID: " . $fileStats[5] . "\n";
      print ORPHFILE "$File::Find::name\n";

    }

  }, $_;

}

close ORPHFILE;

# If no world-writable files have been found ${TMPFILE} should be zero-size;
# Delete it so Tivoli won't alert
if (-z "${OUTDIR}${TMPFILE}") {
  unlink "${OUTDIR}${TMPFILE}";

} else {
  rename("${OUTDIR}${TMPFILE}","${OUTDIR}${PERMFILE}") or die "Cannot rename file ${OUTDIR}${TMPFILE}, $!";

}

显示所有权(或没有所有权)的测试用户的主目录:

drwx------   2          20000          20000   4096 Apr  9 19:59 test

用于将文件 GID 与系统上现有的 GID 进行比较的正则表达式:

(?-xism:0|1|2|3|4|5|6|7|8|9|10|12|14|15|20|30|39|40|50|54|63|99|100|81|22|35|19|69|32|173|11|33|18|48|68|38|499|76|90|89|156|157|158|67|77|74|177|72|21|501|502|10000|10001|10002|10004|10005|10006|5001|5002|5005|5003|10007|10008|10009|10012|10514|47|51|6000|88|5998)

我的逻辑缺少什么?

【问题讨论】:

    标签: linux perl scripting


    【解决方案1】:

    我真的推荐使用 find2perl 来通过不同的属性来定位文件。虽然不如 File::Find 或 File::Find::Rule 漂亮,但它可以为您工作。

    mori@liberty ~ $ find2perl -nouser
    #! /usr/bin/perl -w
        eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
            if 0; #$running_under_some_shell
    
    use strict;
    use File::Find ();
    
    # Set the variable $File::Find::dont_use_nlink if you're using AFS,
    # since AFS cheats.
    
    # for the convenience of &wanted calls, including -eval statements:
    use vars qw/*name *dir *prune/;
    *name   = *File::Find::name;
    *dir    = *File::Find::dir;
    *prune  = *File::Find::prune;
    
    sub wanted;
    
    
    my (%uid, %user);
    while (my ($name, $pw, $uid) = getpwent) {
        $uid{$name} = $uid{$uid} = $uid;
    }
    
    
    # Traverse desired filesystems
    File::Find::find({wanted => \&wanted}, '.');
    exit;
    
    
    sub wanted {
        my ($dev,$ino,$mode,$nlink,$uid,$gid);
    
        (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
        !exists $uid{$uid}
        && print("$name\n");
    }
    

    【讨论】:

    • 哇。这很方便。如何确保我只搜索本地安装的目录而不是远程目录?
    • 我想我可以做很多我已经拥有的事情,例如搜索 /etc/mtab 以查找本地安装并将每个依次传递给 File::Find::find,嗯?
    • 你可以遍历 mtab 并传递给:File::Find::find({wanted => \&wanted}, $dir); $dir 是你的迭代器
    【解决方案2】:
    '20000' =~ /(0|1|2|...)/
    

    匹配。您可能想要锚定表达式:

    /^(0|1|2|...)$/
    

    (另一个答案更好,只是为了完整性而添加。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-08
      • 2015-09-24
      • 1970-01-01
      • 1970-01-01
      • 2011-02-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多