如何从 bash 中的文件名列表中删除文件扩展名

如何从 bash 中的文件名列表中删除文件扩展名

我试图从使用以下 bash 脚本生成的文件列表中删除文件扩展名:

 #!/bin/bash
 file_list=$(find . -type f) #assuming that the files are stored in the same directory
 trimmed_file_list=$(printf '%s\n' "${file_list[@]%.*}")
 printf '%s\n' "${trimmed_file_list[@]}"

此扩展修剪了扩展最后的列表中的条目,但不是任何较早的条目。

例如我想要以下列表:

 file1.pdf
 file2.pdf
 file3.png

成为

 file1
 file2
 file3

但我得到的是:

 file1.pdf
 file2.pdf
 file3

我不想在循环中执行此操作,我想使用参数扩展。我想避免剪切,因为我只想删除文件中的最后一个扩展名。

关于参数扩展有相当多的主题,并且 bash 似乎可能因find使用换行符而令人窒息......我真的不确定。如果另一个预先存在的主题解释了这个问题,我并不完全理解发生了什么。

看似相关但似乎无法解决我的问题的主题:

答案1

您可以通过一个命令完成所有操作。

find /path/to -type f -execdir bash -c 'printf "%s\n" "${@%.*}"' bash {} +

答案2

我相信你会想要创建一个数组而不是字符串:

IFS=$'\n' # split on newline only
set -o noglob # disable the glob part
file_list=($(find . -name '*.*' -type f))

或者使用 bash 4.4+,不要用换行符破坏文件路径:

readarray -td '' file_list < <(find . -name '*.*' -type f -print0)

然后你的参数扩展应该可以工作,尽管在这里再次使用数组变量会更有意义:

trimmed_file_list=("${file_list[@]%.*}")

在您的代码示例中,您正在创建一个字符串,然后要求参数扩展以删除完整字符串中最后一个点字符之后的所有内容。

答案3

您的代码不包含任何数组。此外,它将文件名列表放入字符串$file_list.字符串的内容将以 结尾file3.png,并且您的参数替换将从.png字符串中删除,留下一个文件名字符串,其中最后一个文件名没有文件名后缀。

将多个单独的对象(路径名)放入单个字符串中会自动取消脚本对名称包含空格(或字符串使用的任何分隔符)的文件正常工作的资格。使用数组不会有帮助,因为您仍然会分割find空白的输出。


要删除当前目录中或以下常规文件的所有文件名的扩展名:

find . -type f -name "*.*" -exec sh -c '
    for pathname do
        printf "Would move %s to %s...\n" "$pathname" "${pathname%.*}"
        # mv -i "$pathname" "${pathname%.*}"
    done' sh {} +

这将查找名称至少包含一个点的常规文件。这些文件的路径名被批量输入到循环它们的小 shell 脚本中。 shell 脚本通过删除文件名中的最后一个点及其后的所有内容来重命名文件。为了安全起见,实际mv命令被注释掉。

find命令充当内部 shell 脚本的路径名生成器,保证我们能够正确处理包含空格、换行符和制表符的路径名。无需将命令的输出存储在变量中。

如果您有一个路径名数组,可能是通过使用创建的

shopt -s globstar nullglob
file_list=( **/*.* )  # get pathnames of files with dots in their names

然后你就可以输出没有后缀的路径名

printf '%s\n' "${file_list[@]%.*}"

我不知道这是否对你有帮助。如果你想使用没有后缀的路径名,那么使用上述命令的输出printf将是错误的要做的事情(你会回来不再处理奇怪的路径名)。因此,何时以及如何删除文件名后缀取决于您想要对结果执行的操作。

有关的:

相关内容