grep 从文本文件中读取文件名,并将调用该文件的 shell 文件的名称打印到文本中

grep 从文本文件中读取文件名,并将调用该文件的 shell 文件的名称打印到文本中

我有一些脚本名称及其路径存储在文本文件中。文本文件包含类似的路径

 /myhome/new1/myfiles/test2.sh
 /myhome/new3/myfiles/test1.sh
 /myhome/new2/myfiles/test4.sh
 /myhome/new/myfiles/test5.sh

这些 shell 文件正在被一些主脚本调用

  • 我想要走该路径,主要路径存在于路径中(我不知道如何获取路径,无法 sed 最后一个分隔符)

  • 我想 grep 文件名(以获取文件名使用sed 's/.*\///' new.txt)并存储shell 类型的文件名脚本写入文本文件。

输出在文本文件应该类似于路径、脚本名称和主脚本名称

 /myhome/new1/myfiles/test2.sh  test2    test2main.sh
 /myhome/new3/myfiles/test1.sh  test1    test1foo.sh
 /myhome/new2/myfiles/test4.sh  test4    test4bar.sh
 /myhome/new/myfiles/test5.sh   test5    baz5main.sh

test2main.sh, test1foo.sh, testo4bar.sh... 是调用这些文件的主要脚本。

答案1

您可以使用以下脚本来实现此目的。从您的问题来看,尚不清楚您如何准确确定每个输入文件的“主”文件。在下面的脚本中,简单地假设它是文件夹中唯一的其他文件。

#!/usr/bin/env bash

while IFS= read -r f  # every line is represented by $f
do
    d=$(dirname "$f") # $f's directory
    b=$(basename "$f") # $f's basename
    bwoe=${b%.*} # $f's basename without extension
    m=$(find "$d" -mindepth 1 -maxdepth 1 -not -name "$b" | head -n 1) # get first file in the folder that is not $f
    m=$(basename "$m") # basename of main file
    printf "%s\\t%s\\t%s\\n" "$f" "$bwoe" "$m"
done < input.txt # input.txt contains the input scripts

例子:

$ ls a b c
a:
afoo.sh  a.sh

b:
bmain.sh  b.sh

c:
c.sh  cxx.sh
$ cat input.txt 
a/a.sh
b/b.sh
c/c.sh
$ bash script.sh 
a/a.sh  a       afoo.sh
b/b.sh  b       bmain.sh
c/c.sh  c       cxx.sh

答案2

如果我理解正确(请参阅评论),该命令的 GNUsed标志e可以s帮助您使其成为单行代码(未经测试,抱歉):

sed -E 'h;s_(.*/)(.*)_grep -l \2 \1*.sh_e;x;G;s_([^/]*).sh\n_\1.sh \1 _' scriptfile
  • h将线路保存在保留空间中,以便我们稍后在搞乱后可以恢复它
  • s_.*/_grep -l \2 \1*.sh_e真正的技巧是:.*/匹配最后一个斜杠之前的所有内容,因此\1将是路径,而\2将是该行的其余部分(脚本名称)。 Nowgrep -l插入到脚本名称之前和路径之前;这样/my/path/foo.sh就变成了grep -l foo.sh /my/path/*.sh。该标志在 shell 中执行此模式,因此它被包含的文件e列表替换(希望只有一个,否则需要调整脚本)*.sh/my/pathfoo.sh
  • 其余的很简单:x更改两个缓冲区并将保留缓冲区(现在带有 shell 的答案)附加到模式
  • s_([^/]*).sh\n_\1.sh \1 _进行清理,复制脚本名称(不带.sh)并删除换行符,因此您应该获得所需的输出

答案3

这里c-shell可以成为真正的救世主:

% foreach line ( "`cat ./input.txt`" )
   printf '%s\t%s\t' ${line:q} ${line:r:t:q}
   printf '%smain\n' ${line:r:t:q}
end

其他方法有:

$ perl -F/ -pale '
   my($t) = $F[-1] =~ /([^.]+)/;
   $_ = join "\t", $_, $t, "${t}main" if /\S/;
' ./input.txt

$ sed -Ee '
   s|([^/.]+)\.[^/.]+$|&\t\1\t\1main|;t
   s|([^.]+)\.[^.]+$|&\t\1\t\1main|;t
   s|([^/]+)$|&\t\1\t\1main|
' ./input.txt

结果:

/myhome/new1/myfiles/test2.sh   test2   test2main
/myhome/new3/myfiles/test1.sh   test1   test1main
/myhome/new2/myfiles/test4.sh   test4   test4main
/myhome/new/myfiles/test5.sh    test5   test5main

笔记:

o We have to be verbose as we need to cover the various possible cases that may arise.
o GNU sed is needed.

答案4

您可以使用 sed 中的捕获组和扩展正则表达式(-r 选项)来获取文件名并在最终输出中将原始字符串与脚本一起替换:

sed -r 's/(^.*\/)([^.]*)(.*$)/\1\2\3 \2 \2main/' test.txt 

(^.*\/) -- 1st Capture, the path 
([^.]*) -- 2nd Capture, the file up to the dot 
(.*$)   -- 3rd Capture, the file suffix 

相关内容