我有一个包含以下行的文件:
文件1
./filled/Event_repeatFILLED.svelte
./dir2/Miscellaneous_servicesFILLED.svelte
./outline/Line_weightFILLED.svelte
./two-tone/ArchitectureFILLED.svelte
...many more lines ...
我想创建一个仅包含基名的文件:
文件2
Event_repeatFILLED.svelte
Miscellaneous_servicesFILLED.svelte
Line_weightFILLED.svelte
ArchitectureFILLED.svelte
...
目前以下内容不起作用。
sed 's/^.\///' file1 > file2
我如何使用 Shell/Bash 来做到这一点?
答案1
您需要在 sed 替换命令中使用不同的分隔符。例如:
$ sed 's|.*/||' file
Event_repeatFILLED.svelte
Miscellaneous_servicesFILLED.svelte
Line_weightFILLED.svelte
ArchitectureFILLED.svelte
...many more lines ...
或者:
$ perl -pe 's|.*/||' file
Event_repeatFILLED.svelte
Miscellaneous_servicesFILLED.svelte
Line_weightFILLED.svelte
ArchitectureFILLED.svelte
...many more lines ...
或者,与awk
:
$ awk -F'/' '{print $NF}' file
Event_repeatFILLED.svelte
Miscellaneous_servicesFILLED.svelte
Line_weightFILLED.svelte
ArchitectureFILLED.svelte
...many more lines ...
或者甚至是一些愚蠢的事情,例如:
$ rev file | cut -d / -f 1 | rev
Event_repeatFILLED.svelte
Miscellaneous_servicesFILLED.svelte
Line_weightFILLED.svelte
ArchitectureFILLED.svelte
...many more lines ...
或者您可以按照评论中的建议使用basename
,但这会更复杂且更慢:
$ while IFS= read -r fileName; do basename -- "$fileName"; done < file
Event_repeatFILLED.svelte
Miscellaneous_servicesFILLED.svelte
Line_weightFILLED.svelte
ArchitectureFILLED.svelte
最后,如果你真的想要一个纯 shell 解决方案,你可以这样做:
$ while IFS= read -r fileName; do printf '%s\n' "${fileName##*/}"; done < file
Event_repeatFILLED.svelte
Miscellaneous_servicesFILLED.svelte
Line_weightFILLED.svelte
ArchitectureFILLED.svelte
...many more lines ...
但不要使用最后两个,它们效率最低且最复杂。看为什么使用 shell 循环处理文本被认为是不好的做法?。
答案2
xargs
通过和的 GNU 实现basename
,您可以执行以下操作:
xargs -rd '\n' -a file1 basename -a -- > file2
使用的basename
优点是可以正确处理一些特殊情况,例如/
or /some/dir/
。
手动执行等效操作:
LC_ALL=C sed -e 's:^//*$:/:;t' -e 's:/*$::; s:.*/::' < file1 > file2
LC_ALL=C
需要,因为文件路径不能保证由区域设置中的有效文本组成/
或//
,///
... 首先进行特殊处理- 尾随
/
s 已删除 - 然后将所有内容剥离到最右边
/
。
如果使用zsh
,您还可以使用它的:t
(for t
ail) 修饰符(借自csh
):
print -rC1 -- ${${(f)"$(<file1)"}:t} > file2
请注意,对于/
(or //
, ///
...) 它与 GNU 的不同之处basename
在于它返回空字符串而不是/
。
和perl
:
perl -MFile::Basename -lpe '$_=basename$_' < file1 > file2
答案3
不要太深入,你的命令的直接问题是点的意思是“任何一正则表达式中的“字符”。您需要.*
匹配任意数量的字符(在标准正则表达式中尽可能多)。
所以尝试一下
sed 's/^.*\///' file1 > file2
其他答案和评论中提到的注意事项适用。