Answers:
使用以下任何一种方式:
out_file="${in_file##*/}"
out_file="$(basename $in_file)"
out_file="$(echo $in_file | sed 's=.*/==')"
out_file="$(echo $in_file | awk -F"/" '{ print $NF }')"
ps。之所以得到相同的字符串,是因为在语句\(.*\.\)
中,它从开始到点(/root/video.
)都与该字符串匹配,然后手动添加.mp4
与原始字符串相同的字符串。您应该s=.*\([^/]*\)=\1=
改用。
更新:(第一个已修复)
要获取唯一不带扩展名的文件名,您可以:
out_file="$(echo $in_file | sed 's=.*/==;s/\.[^.]*$/.new_ext/')"
out_file="$(echo $in_file | sed 's=\([^/]*\)\.[^./]*$=\1.new_ext=')"
out_file="$(echo $in_file | awk -F"/" '{ gsub (/\.[^/.]*$/,".new_ext",$NF);print $NF }'
my.file.tar.gz
。
sed
和缺少一个点符号awk
。固定。谢谢。
使用正则表达式的基本原理之一是,在指定通配符时,模式本质上是贪婪的。虽然@uloBasEI提出的答案肯定是一个可行的答案,但它也需要使用basename命令。@Shixons的原始问题要求仅使用sed的解决方案。
在继续之前,了解目标版本的sed总是有帮助的。我假设BSD(与OSX一起提供)。
首先,原始问题中提出的模式不起作用,因为它会捕获从输入字符串的开始到最后一个点(包括最后一个点)的所有内容。没有锚点,此搜索将吞噬所有从左到右的内容。因此,“ / 1”匹配模式是直到最后一个点(包括最后一个点)的所有内容。即使是带有多个点的文件名也会被整个吞没。根本达不到预期的结果。
第一步是建立识别模式的策略。在这里,您想摆脱文件名左侧的所有内容(稍后我们将处理扩展名):
out_file="$(echo $in_file | sed 's/^\(\/.*\/\)*.*/\1/')"
搜索从字符串的开头开始匹配。它与“ /.*”模式匹配零次或更多次,然后删除所有内容。我们用“ \ 1”打印匹配的模式。我们不在全球范围内搜索;我们通过指定^锚从字符串的开头进行搜索。
通过启用“ -E”选项,我们可以获得更好的清晰度,因此我们不必转义括号:
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*.*/\1/')"
因此,现在我们在左侧。让我们在右侧添加零件。请注意,我们需要将左侧部分保留为模式,因为这是我们可以指定左侧部分出现零次或多次的方式。我们现在要做的就是在右侧的部分添加一个模式:
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)/\2/')"
我们仅打印出第二个匹配项,从而丢弃文件名以外的所有内容。但是我们仍然需要删除文件扩展名。
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2/')"
最后的“ $”是可选的。
最后,要添加新的扩展名,您需要像这样修改:
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2.mp4/')"
另一个优化是使第一个正斜杠成为可选选项以处理相对路径:
out_file="$(echo $in_file | sed -E 's/^([\/]?.*\/)*(.*)\..*$/\2.mp4/')"
我在寻找sed模式来替换basename时很懒,从而遇到了这个问题。我正在未安装该命令的剥离系统上工作。
sed 's/\.[^.]*$//'
你有,将失败(隐藏).filename
和.
与..
目录