一行中列出Bash脚本文件名的扩展名列表

4

我目前有以下代码行:

ls /some/dir/prefix* | sed -e 's/prefix.//' | tr '\n' ' '

这个代码实现了我想要的功能:

  • 获取以指定前缀开头的文件列表
  • 从每个字符串中去除路径和前缀
  • 移除换行符并用空格代替以便后续处理。

例如:

/some/dir/prefix.hello
/some/dir/prefix.world

Should become

hello world

但我感觉有更好的方法来做这件事。有没有更好的一行代码实现的方法?


1
你似乎不仅删除了 prefix,还删除了下一个字符。这是你想要的吗? - Benjamin W.
@BenjaminW。是的,我想要前缀和.,我需要文件扩展名列表。 - Jordan Mackie
1
那么,字面上的句点,对吗? - Benjamin W.
@BenjaminW,好的。我会在问题中添加一些例子。 - Jordan Mackie
2
https://mywiki.wooledge.org/ParsingLs - Biffen
1
你需要使用 ls 程序吗?用 echo 不行吗? - cdarke
4个回答

4
这里有一个只使用内置函数的两行代码,可以实现此功能:
fnames=(some/dir/prefix*)
echo "${fnames[@]##*.}"

这是如何工作的:
  • fnames=(some/dir/prefix*)创建一个数组,其中包含以 prefix 开头的所有文件,并避免解析 ls 带来的所有问题。
  • echo "${fnames[@]##*.}"是两个参数扩展的组合:${fnames[@]}打印所有数组元素,##*. 部分从每个数组元素中删除以点(.)结尾的任何内容的最长匹配,只留下扩展名。

如果你非要使用一行命令,只需用 && 将两个命令连接起来即可。


遵循这里的建议避免使用ls命令,而您的解决方案更易读,因此我将其标记为已接受,谢谢! - Jordan Mackie
非常简单和不错。 - kvantour

1

ls输出传递给外部程序并不推荐,以下bash解决方案可能会对您有所帮助。

for file in prefix*; do echo ${file##*.}; done

现在还添加了一种非单行解决方案。

for file in prefix*
do
   echo ${file##*.}
done

1
这会每行打印一个文件,但是对于像/path/.has/period/prefix.ext这样的路径会失败,因为它会删除*.的最短匹配。 - Benjamin W.
@BenjaminW.,谢谢你让我知道了,我忽略了它,现在已经添加了。 - RavinderSingh13

1
这里有一个非常简单的 Awk 一行命令可以实现这个需求:
awk -F. '{$0=FILENAME; printf $NF" "; nextfile}' /some/dir/prefix*

它基本上执行以下操作:
-F.:将字段分隔符FS设置为.。这样$NF表示扩展名。 $0=FILENAME:忽略当前记录并将其设置为FILENAME,以此重新解析所有内容。 print $NF; nextfile:打印扩展名并转到下一个文件。
但问题在于该文件仍会读取当前文件的记录。如果该文件为空,则会失败。
要使其在空文件中起作用,可以使用gawk扩展BEGINFILE。
awk -F. 'BEGINFILE{$0=FILENAME; printf $NF" "; nextfile}' /some/dir/prefix*

或者您可以循环遍历所有参数:

awk -F. 'BEGIN{for(i in ARGV){$0=ARGV[i]; printf $NF" "};exit}' /some/dir/prefix*

0
一种使用awk的方法:
ls /some/dir/prefix* | awk -F"." '{printf "%s ", $2} END {print ""}'

这可能被认为是“更好”的,因为只有一个命令输出被管道传输?!


@Iubgr,说实话我们不应该将ls的输出传递给外部程序。 - RavinderSingh13
减少管道命令的数量正是我想要的。我更喜欢Benjamin的答案,因为它更易读(在我看来)。 - Jordan Mackie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接