0

如何与find /tmp -type l -exec ls -l输出中的 $TARGET_NAME 值完全匹配?

 $ find /tmp -type l -exec ls -l 2>/dev/null {} +
 lrwxrwxrwx 1 root root  24 Mar 18 12:41 /tmp/test/link -> /usr/admin/Collect_tests
 lrwxrwxrwx 1 root root  43 Mar 18 12:41 /tmp/test/link1 -> /usr/admin/Collect_tests/Upload.CM@.www.com
 lrwxrwxrwx 1 root root  68 Mar 18 12:41 /tmp/test/link2 -> /usr/admin/Collect_tests/Upload.CM@.www.com/Upload_Shema@@@.DATA.com
 lrwxrwxrwx 1 root root 100 Mar 18 12:42 /tmp/test/link3 -> /usr/admin/Collect_tests/Upload.CM@.www.com/Upload_Shema@@@.DATA.com/List.files.emails.dummy*Printed
 lrwxrwxrwx 1 root root  92 Mar 18 12:42 /tmp/test/link4 -> /usr/admin/Collect_tests/Upload.CM@.www.com/Upload_Shema@@@.DATA.com/List.files@emails.dummy

值的例子

 TARGET_NAME=Upload.CM@.www.com
 TARGET_NAME=Upload_Shema@@@.DATA.com
 TARGET_NAME=List.files.emails.dummy*Printed

目标:仅当 $TARGET_NAME 与最后一个字段中的单词完全匹配时才打印:“链接名称”和“PATH”(最后一个字段)。

示例(当我们想要精确匹配时 - 而TARGET_NAME =Upload_Shema@@@.DATA.com 然后):

结果将显示如下

/tmp/test/link2 /usr/admin/Collect_tests/Upload.CM@.www.com/Upload_Shema@@@.DATA.com
/tmp/test/link3 /usr/admin/Collect_tests/Upload.CM@.www.com/Upload_Shema@@@.DATA.com/List.files.emails.dummy*Printed
/tmp/test/link4 /usr/admin/Collect_tests/Upload.CM@.www.com/Upload_Shema@@@.DATA.com/List.files@emails.dummy

有几个条件:

1)只需要匹配最后一个字段(来自ls -l输出)

例子

      /usr/admin/Collect_tests/Upload.CM@.www.com

2) $TARGET_NAME 值应该匹配整个单词

完全匹配示例(同时TARGET_NAME=Upload.C​​M@.www.com):

    /usr/admin/Collect_tests/Upload.CM@.www.com

非完全匹配示例:

    /usr/admin/Collect_tests/Upload.CM@.www.c

3) $TARGET_NAME 左侧必须存在反斜杠(“/”),$TARGET_NAME 右侧必须找到反斜杠或字符串结尾。

4) 需要将特殊字符转义为:“/”、“ @ ”。“ * ”等

5) 代码将成为 ksh 脚本的一部分(并且可以由 Perl oneliner 或AWK或 ksh 等实现。)

例子

   find /tmp -type l -exec ls -l 2>/dev/null {} + | < Perl one liner .............. >    
4

4 回答 4

0

鉴于以下链接

$ cd /tmp

$ ls -l link* | sed -e 's/^.*\(link\)/\1/'
link -> /usr/admin/Collect_tests
link1 -> /usr/admin/Collect_tests/Upload.CM@.www.com
link2 -> /usr/admin/Collect_tests/Upload.CM@.www.com/Upload_Shema@@@.DATA.com
link3 -> /usr/admin/Collect_tests/Upload.CM@.www.com/Upload_Shema@@@.DATA.com/List.files.emails.dummy*Printed
link4 -> /usr/admin/Collect_tests/Upload.CM@.www.com/Upload_Shema@@@.DATA.com/List.files.emails.dummy
link5 -> /usr/admin/Collect_tests/Upload.CM@.www.com/

使用 File::Find 模块,如

$ TARGET_NAME='Upload_Shema@@@.DATA.com' perl -MFile::Find -le 'find sub {
   -l && defined($dst = readlink $_) &&
   index($dst, $ENV{TARGET_NAME}) >= 0 &&
   print "$File::Find::name $dst" }, @ARGV' /tmp
/tmp/link2 /usr/admin/Collect_tests/Upload.CM@.www.com/Upload_Shema@@@.DATA.com
/tmp/link3 /usr/admin/Collect_tests/Upload.CM@.www.com/Upload_Shema@@@.DATA.com/List.files.emails.dummy*Printed
/tmp/link4 /usr/admin/Collect_tests/Upload.CM@.www.com/Upload_Shema@@@.DATA.com/List.files.emails.dummy

作为一个单线,这真的很笨拙。作为一个单独的命令,它变成

#! /usr/bin/env perl

use strict;
use warnings;

use File::Find;

die "Usage: $0 root-dir ..\n" unless @ARGV;
die "$0: TARGET_NAME is not defined\n" unless exists $ENV{TARGET_NAME};

sub print_matching_target_name {
  return unless -l && defined(my $dst = readlink $_);
  print "$File::Find::name $dst\n" if index($dst, $ENV{TARGET_NAME}) >= 0;
}

find \&print_matching_target_name, @ARGV;

样本输出:

$查找目标
用法:查找目标根目录..

$ 查找目标 /tmp
查找目标:未定义 TARGET_NAME

$ TARGET_NAME=Upload.C​​M@.www.com ./find-target /tmp
/tmp/link2 /usr/admin/Collect_tests/Upload.C​​M@.www.com/Upload_Shema@@@.DATA.com
/tmp/link3 /usr/admin/Collect_tests/Upload.C​​M@.www.com/Upload_Shema@@@.DATA.com/List.files.emails.dummy*打印
/tmp/link4 /usr/admin/Collect_tests/Upload.C​​M@.www.com/Upload_Shema@@@.DATA.com/List.files.emails.dummy
于 2013-03-18T13:08:46.017 回答
0

尝试这样做:

#!/bin/bash

while IFS= read -r file; do
    printf "TARGET_NAME=%q\n" "$file"
done < <(find /tmp -type l -printf '%l\n')

结果是反斜杠的,例如:

TARGET_NAME=/tmp/foo/List.files.emails.dummy\*Printed
于 2013-03-18T13:30:42.650 回答
0

由于目标可能与要返回的部分相同也可能不同,因此进行两个单独的正则表达式调用似乎最容易(如果应该对其进行概括也可能会有所帮助):

perl -ne 'print "$1" if (m#Upload.CM@.www.com# && m#([^/]+)\s*$#);'

换句话说,找到目标短语然后获取 find 的最后一个组件(不包含“/”的组件)。当两个条件都满足时,打印括号中捕获的文本。

关于特殊字符:如果将“#”替换为更传统的“/”,你需要将我写成“/”的那个转义,否则,“@”应该不会给你带来麻烦。当然,如果它在您的系统上运行,只需使用“\”转义它们。

于 2013-03-18T13:53:55.477 回答
0

正如在回答您的上一个问题(已删除)时提到的那样,解析ls输出非常不理想。readlink可以代替使用。

find /tmp -type l -exec \
   perl -e'
      my $TARGET_NAME = shift;
      for (@ARGV) {
         my $p = readlink($_);
         $p =~ m{(?:^|/)\Q$TARGET_NAME\E(?:/|\z)}
            or next;
         print("$_\t$p\n");
      }
   ' "$TARGET_NAME" {} \;

或者更高效,

perl -MFile::Find::Rule -e'
   my ($TARGET_NAME, $BASE) = @ARGV;
   for (File::Find::Rule->symlink->in($BASE)) {
      my $p = readlink($_);
      $p =~ m{(?:^|/)\Q$TARGET_NAME\E(?:/|\z)}
         or next;
      print("$_\t$p\n");
   }
' "$TARGET_NAME" /tmp

根据要求,这将匹配

TARGET_NAME
TARGET_NAME/
TARGET_NAME/x
.../TARGET_NAME
.../TARGET_NAME/
.../TARGET_NAME/x

但不是

TARGET_NAMEx/...
.../TARGET_NAMEx
.../TARGET_NAMEx/...
xTARGET_NAME/...
.../xTARGET_NAME
.../xTARGET_NAME/...

注意:如果您支持,请更改find ... -exec ... \;为。find ... -exec ... +find

于 2013-03-18T22:01:13.817 回答