英文:
Is there a Linux function to check if a filename with differing case exists?
问题
在Linux中,您可以使用以下方法来检查文件名的大小写差异是否存在:
# 尝试打开文件(尝试 *Hello.txt*)
if [ -e "Hello.txt" ]; then
echo "File exists with the same case."
else
# 检查文件夹中是否存在不同大小写的文件(查找文件 *hello.txt*)
lowercase_file=$(find . -name "hello.txt" -print -quit)
if [ -n "$lowercase_file" ]; then
echo "File with different case exists: $lowercase_file"
else
echo "File not found."
fi
fi
这段代码首先尝试打开指定的文件(Hello.txt),如果失败,则在同一目录中查找是否存在不同大小写的文件(hello.txt)。
英文:
Is there a Linux function to check if a filename with differing case exists? e.g. to find the difference between Hello.txt and hello.txt
For example if I wanted to open Hello.txt I would like to do:
- try to open a file ( try Hello.txt)
if that fails:
- check if there is a file with different case in the folder (find file hello.txt)
答案1
得分: 3
没有,你需要迭代目录中的文件并手动进行检查。不过,有一些函数可以帮助处理这个问题,例如 scandir
。自从 C++17 开始,你可以使用 std::filesystem::directory_iterator
来遍历目录,还可以使用标准库中的通用算法来辅助实现,如果需要的话。
另外,某些文件系统是不区分大小写的,它们将认为这两个文件名是等效的。但一般来说,Linux 将文件名视为字节值序列。因此,如果文件名中包含非ASCII值,你还需要决定要如何解释文件名的编码。如果假定使用Unicode编码,那么确切地理解"不同大小写"意味着什么也不是简单的。
英文:
No, there isn't. You'll need to iterate the files in the directory and do the check manually. There are functions to help with that though, e.g. scandir
. Since C++17 you have std::filesystem::directory_iterator
to iterate through the directory and generic algorithms in the standard library to help with the implementation if needed.
Also, some file systems are case-insensitive and will consider these two equivalent file names anyway. But in general Linux considers file names as just a sequence of byte values. So you will also need to decide in what encoding you want to interpret the file name if there are non-ASCII value in there. If you assume a Unicode encoding, figuring out what exactly "differing case" means is also not trivial.
答案2
得分: 2
如果存在这样的函数,将有2<sup>n</sup>个组合要检查,其中`n`是文件名的长度。
对于`hello.txt`,如果包括扩展名,将有256种检查方式(2<sup>8</sup> = 256)。随着n的增长,由于指数时间复杂度,它会非常快地变成一个难以管理的问题。
这是非常低效的,因此执行不区分大小写的文件名匹配的最佳方法是将所有内容转换为小写(或大写),然后进行比较,就像@mark-setchell指出的那样。
由于你标记了C++和Linux,我已经包含了一个在Linux上运行的解决方案,用C++编写。请记住`strcasecmp`函数仅存在于Linux系统上。
此外,如果我们跟踪匹配的索引,如果需要确切的区分大小写的文件名,就无需遍历2<sup>n</sup>次迭代。
英文:
If such function were to exist, there will be 2<sup>n</sup> combinations to check where n
is the length of the file name.
For hello.txt
, if you include the extension, there will be 256 ways to check (2<sup>8</sup> = 256). As with exponential time complexity, it becomes an unmanageable problem very fast as n grows.
This is hugely inefficient and so the best way to do case-insensitive filename match is to convert everything to lower (or upper) case and then compare them like @mark-setchell points out.
Since you tagged c++ and linux, I have included a solution which works on linux, written in c++. Remember the function strcasecmp
is only present on linux systems.
Also, if we keep track of the index of the match, we need not go through the 2<sup>n</sup> iterations if we need the exact case sensitive file name.
#include <iostream>
#include <filesystem>
#include <vector>
#include <cstring>
#include <algorithm>
int main() {
std::string path = "./";
std::string to_find = "hello.txt";
bool exists = false;
int found_index = 0;
std::vector<std::string> arr;
for (const auto &entry: std::filesystem::directory_iterator(path)) {
arr.push_back(entry.path());
}
std::sort(arr.begin(), arr.end()); //std::filesytem::directory_iterator's
//order cannot be determined, so the
//vector is sorted. This step is optional though
for (int i=0; i<arr.size(); i++) {
std::string a = arr[i].substr(path.size()); // Remove prefix path
if (strcasecmp(a.c_str(), to_find.c_str()) == 0) {
exists = true;
found_index = i;
break;
}
}
if (exists) {
std::cout << "File found and the exact file name is \"" << arr[found_index] << "\"" << std::endl;
} else {
std::cout << "File not found" << std::endl;
}
}
If match is found the above program prints out the exact file name too.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论