Linux Perl oneliner将路径中的确切单词与许多具有特殊字符的不同值进行匹配

Linux Perl oneliner将路径中的确切单词与许多具有特殊字符的不同值进行匹配,linux,perl,bash,ksh,ls,Linux,Perl,Bash,Ksh,Ls,如何精确匹配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 ->

如何精确匹配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\u name 精确匹配最后一个字段中的单词

示例(当我们希望精确匹配-whileTARGET\u NAME=Upload\u 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
output)

范例

      /usr/admin/Collect_tests/Upload.CM@.www.com
2) $TARGET\u NAME值应与整个单词匹配

完全匹配的示例(而TARGET\u NAME=Upload)。CM@.www.com):

非完全匹配的示例:

    /usr/admin/Collect_tests/Upload.CM@.www.c
3) 反斜杠(“/”)必须位于$TARGET\u NAME的左侧,反斜杠或字符串的结尾必须位于$TARGET\u NAME的右侧

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

5) 代码将是ksh脚本的一部分(可以由Perl oneliner或ksh等实现)

示例

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

提供以下链接

$ 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/
使用文件::查找模块,如中所示

$ 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;
样本输出:

$ find-target Usage: find-target root-dir .. $ find-target /tmp find-target: TARGET_NAME is not defined $ TARGET_NAME=Upload.CM@.www.com ./find-target /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 $find目标 用法:查找目标根目录。。 $find target/tmp 查找目标:未定义目标名称 $TARGET_NAME=上传。CM@.www.com/查找目标/tmp /tmp/link2/usr/admin/Collect_测试/上传。CM@.www.com/上传_Shema@@@DATA.com /tmp/link3/usr/admin/Collect_测试/上传。CM@.www.com/上传_Shema@@@DATA.com/List.files.emails.dummy*打印 /tmp/link4/usr/admin/Collect_测试/上传。CM@.www.com/上载_Shema@@@DATA.com/List.files.emails.dummy尝试执行以下操作:

#!/bin/bash

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

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

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

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

对它们进行转义,正如您在回答上一个问题时提到的(自删除后),解析
ls
输出是非常不理想的<代码>读取链接可以改为使用

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
支持它。

?不要解析ls输出,即使它来自
find
@Sputnick我没有其他选择(我需要验证链接指向的所有路径)是的,您可以举例说明:
find-type l-printf“%l\n”
这是一个更好的开始。@Sputnick thx,这是我的新信息为什么不打印“TARGET\u NAME=%q\n'$file”
?另外,为什么要使用两个“-printf“%l\n”选项来
find
?@Sputnick为什么在“*”之前打印“\”,输出应该与相应编辑的目录/文件名相同。删除了一个打字错误并添加了一个improvement@Eytan,这是为了满足以下要求:
4)需要将特殊字符转义为:“/”、“@”。“*”,etc
请注意,如果链接目标包含任何字符(如嵌入换行符),则
printf“%q”
的输出将包含类似bash的
$'foo\nbar'
。这些要求没有规定如何处理这种情况。是否可以在“TARGET\u NAME”之前打印链接文件,例如:/tmp/link TARGET\u NAME=Upload。CM@.www.comany为什么我的问题的目标是验证$target_NAME值在路径(最后一个字段)中是否匹配,我不想只打印每个路径的基本名称-目标是将$target_名称与输出(最后一个字段路径)匹配@Eytan我知道您现在在寻找什么。参见更新的answer.thanx,还有一个问题如果我还想打印完整的$TARGET\u名称,我需要设置:print“$File::Find::NAME$b”$ENV{TARGET\u NAME},@ARGV'/tmp???我需要的示例:/tmp/test/link2 Upload\u Shema@@@DATA.com/usr/admin/Collect\u tests/Upload。CM@.www.com/上传_Shema@@@DATA.com(这句话和我告诉Olaf的话是一样的)如果我设置了TARGET_NAME=Collect_tests,那么我希望看到6行匹配的“查看我的查询详细信息”,所以…(对于所有链接,link1、link2、link3、link4、link5)代码仅打印链接收集测试备注-我希望打印与$TARGET\u名称匹配的所有行的原因,因为我以后需要重新创建新链接第二个问题代码无法在solaris 10上工作…无法理解此问题?(无任何代码输出)ug,你的帖子与你的第一条评论完全相反。我已经修正了你的问题,并相应地调整了我的答案。如果你不告诉我问题是什么,我就无法修正你的Solaris问题。(
find
不会产生任何结果?
@ARGV
empty?Regex不匹配?)你知道为什么你的第一个代码不适合solaris 10吗?(它只在linux上运行)
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/...