我正在尝试通过在 bash 中使用以下命令提取目录my-repo/text/*/<file_name>.txt中的 txt 文件名
echo "my-repo/text/level1_dir/der.txt my-repo/scripts/af.py my-repo/text/level1_dir/another/er_abc.txt my-repo/text/deep/nested/my-file.txt" | sed -E 's|my-repo/text/.*/([^/]+)\.txt|\1|g'
但我得到以下输出:my-file
,而我需要的输出是der
er_abc
my-file
。
有办法吗?
2
8 个解决方案
8
你可以使用这个tr | sed
解决方案:
echo "my-repo/text/level1_dir/der.txt my-repo/scripts/af.py my-repo/text/level1_dir/another/er_abc.txt my-repo/text/deep/nested/my-file.txt" |
tr ' ' '\n' |
sed -E '/\.txt$/!d; s|my-repo/text/[^ ]+/([^/.]+)\.txt|\1|g'
der
er_abc
my-file
|
如果 GNUawk
是一个选项,则将记录分隔符设置为空格,匹配扩展上的一行,并打印它之前的所有内容,而不是路径分隔符:
echo … | awk -v RS='\\s' 'match($0, /([^/]+)\.txt$/, a) {print a[1]}'
或者,也将字段分隔符设置为点或斜线,检查最后一个字段并打印倒数第二个字段(假设文件名中没有出现其他点):
echo … | awk -v RS='[[:space:]]' -F '[/.]' '$NF=="txt" {print $(NF-1)}'
输出:
der
er_abc
my-file
|
使用这个 Perl 单行命令:
echo "my-repo/text/level1_dir/der.txt my-repo/scripts/af.py my-repo/text/level1_dir/another/er_abc.txt my-repo/text/deep/nested/my-file.txt" | perl -lane 'print join " ", map { m{([^/]+)[.]txt$} } @F;'
Perl 单行命令使用下列命令行标志::
-e
告诉 Perl 在行内查找代码,而不是在文件中。
-n
:一次循环输入一行,$_
默认将其分配给。
-l
:在行内执行代码之前删除输入行分隔符("\n"
默认在 *NIX 上),并在打印时附加它。
-a
:在空格或选项中指定的正则$_
表达式上拆分成数组。@F
-F
map { m{([^/]+)[.]txt$} } @F
:对于数组的每个元素@F
(= 对于每个路径),返回与正则表达式匹配的捕获字符串(如果有)([^/]+)[.]txt$
。:
([^/]+)[.]txt$
捕获文件的基本名称.txt
。
([^/]+)
:除“/”(斜杠)之外的任何字符出现 1 次或多次,捕获(使用括号)并返回。
[.]
:文字点。
txt$
:txt
字符串后跟行尾。
参见:
|
find
如果从 而不是开始echo
,那么任务就更容易了:
find my-repo/text/ -type f -name '*.txt' -exec basename {} '.txt' \;
.txt
这将在目录树中查找带有扩展名的文件my-repo/text/
,并打印它们的基本文件名,删除目录名和扩展名.txt
。
|
使用find
内置printf
语句,您可以轻松实现您的目标
$ find /path/to/search/dir -type f -name '*.txt' -printf '%f\n'
或者如果你想使用 NULL 分隔符
$ find /path/to/search/dir -type f -name '*.txt' -printf '%f\0'
|
一种bash
方法是使用 globstar
和nullglob
名
#!/usr/bin/env bash
shopt -s globstar nullglob
files=(./my-repo/**/*.txt)
basename -s '.txt' "${files[@]}"
使用mapfile
和
shopt -s globstar nullglob
mapfile -t files < <(basename -s '.txt' ./my-repo/**/*.txt)
如果没有basename
bash 内部的替代方法是使用
files=("${files[@]##*/}")
files=("${files[@]%.txt}")
printf '%s\n' "${files[@]}"
|
这可能对你有用(GNU sed):
sed -E 's/ *my-repo\S*\/(\S+)\.txt|\S+/\1\n/;/^\S/P;D' file
如果行首以可选空格开头,后跟my-repo
,后跟零个或多个非空格字符,后跟一个正斜杠,后跟一个或多个非空格字符,后跟.txt
,则将其替换为最后一个正斜杠与字符串.txt
和换行符之间的字符串。否则,只需将该字符串替换为换行符。
如果现在行首包含一个无空格字符,则打印直至换行符为止。
删除直至换行符并重新执行。
注意:该/^regexp/P;D
模式会逐渐减少包含换行符的行,打印或不打印直到第一个换行符,直到该行完全被消耗掉。
|
要提取您描述的文件名,可以使用以下 bash 命令:
echo "my-repo/text/level1_dir/der.txt my-repo/scripts/af.py my-repo/text/level1_dir/another/er_abc.txt my-repo/text/deep/nested/my-file.txt" | grep -oP 'my-repo/text/.*?/\K[^/]+(?=\.txt)'
|
echo
命令的字符串。我没有看到任何实际访问目录的命令。此外,当您描述所需的输出时,从您的写作中不清楚您是否需要一个名称数组,还是一个包含所有名称的单个字符串。如果您需要一个字符串,那么如何在字符串内分隔名称?–
–
|