There should be something elegant in Linux API/POSIX to extract base file name from full path. Thank you.
Linux API / POSIX中应该有一些优雅的东西可以从完整路径中提取基本文件名。谢谢。
9 个解决方案
#1
37
See char *basename(char *path)
.
请参见char * basename(char * path)。
Or run the command "man 3 basename
" on your target UNIX/POSIX system.
或者在目标UNIX / POSIX系统上运行命令“man 3 basename”。
#2
13
Use basename
(which has odd corner case semantics) or do it yourself by calling strrchr(pathname, '/')
and treating the whole string as a basename if it does not contain a '/'
character.
使用basename(具有奇数的case case语义)或者通过调用strrchr(pathname,'/')并将整个字符串视为基本名称(如果它不包含'/'字符)来自行完成。
#3
4
Here's an example of a one-liner (given char * whoami
) which illustrates the basic algorithm:
这是一个单行(给定char * whoami)的例子,它说明了基本算法:
(whoami = strrchr(argv[0], '/')) ? ++whoami : (whoami = argv[0]);
an additional check is needed if NULL is a possibility. Also note that this just points into the original string -- a "strdup()
" may be appropriate.
如果可能为NULL,则需要进行额外检查。另请注意,这只是指向原始字符串 - “strdup()”可能是合适的。
#4
1
You could use strstr
in case you are interested in the directory names too:
如果您对目录名称感兴趣,也可以使用strstr:
char *path ="ab/cde/fg.out";
char *ssc;
int l = 0;
ssc = strstr(path, "/");
do{
l = strlen(ssc) + 1;
path = &path[strlen(path)-l+2];
ssc = strstr(path, "/");
}while(ssc);
printf("%s\n", path);
#5
1
Of course if this is a Gnu/Linux only question then you could use the library functions.
当然,如果这只是一个Gnu / Linux问题,那么你可以使用库函数。
https://linux.die.net/man/3/basename
https://linux.die.net/man/3/basename
And though some may disapprove these POSIX compliant Gnu Library functions do not use const. As library utility functions rarely do. If that is important to you I guess you will have to stick to your own functionality or maybe the following will be more to your taste?
虽然有些人可能不赞成这些符合POSIX标准的Gnu库函数,但不使用const。由于库实用程序功能很少。如果这对你很重要,我想你必须坚持自己的功能,或者以下更符合你的口味?
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *fn;
char *input;
if (argc > 1)
input = argv[1];
else
input = argv[0];
/* handle trailing '/' e.g.
input == "/home/me/myprogram/" */
if (input[(strlen(input) - 1)] == '/')
input[(strlen(input) - 1)] = '\0';
(fn = strrchr(input, '/')) ? ++fn : (fn = input);
printf("%s\n", fn);
return 0;
}
#6
1
The basename()
function returns the last component of a path, which could be a folder name and not a file name. There are two versions of the basename()
function: the GNU version and the POSIX version.
basename()函数返回路径的最后一个组件,该组件可以是文件夹名称而不是文件名。 basename()函数有两个版本:GNU版本和POSIX版本。
The GNU version can be found in string.h
after you include #define _GNU_SOURCE
:
在包含#define _GNU_SOURCE之后,可以在string.h中找到GNU版本:
#define _GNU_SOURCE #include <string.h>
The GNU version uses const
and does not modify the argument.
GNU版本使用const而不修改参数。
char * basename (const char *path)
This function is overridden by the XPG (POSIX) version if libgen.h
is included.
如果包含libgen.h,则XPG(POSIX)版本会覆盖此函数。
char * basename (char *path)
This function may modify the argument by removing trailing '/' bytes. The result may be different from the GNU version in this case:
此函数可以通过删除尾随的'/'字节来修改参数。在这种情况下,结果可能与GNU版本不同:
basename("foo/bar/")
will return the string "bar" if you use the XPG version and an empty string if you use the GNU version.
如果使用XPG版本将返回字符串“bar”,如果使用GNU版本,则返回空字符串。
References:
参考文献:
-
basename (3) - Linux Man Pages
-
Function: char * basename (const char *filename), Finding Tokens in a String.
#7
0
I don't want to be nit-picking here on what other people post but...
我不想在这里发布其他人发帖但是......
- Calling some suggested "homemade" functions (such as:
getFileNameFromPath("")
) will crash the program. - 调用一些建议的“自制”函数(例如:getFileNameFromPath(“”))将使程序崩溃。
- I would recommend some caution when naming functions that inherently claims that the result will be a file.
getFilenameFromPath("/usr/local")
will return"local"
(without the quotation marks) although on a unix file system it is usually the case that it is a folder. - 我建议在命名函数时要小心,这些函数本身声称结果将是file.getFilenameFromPath(“/ usr / local”)将返回“local”(不带引号),尽管在unix文件系统上通常就是这种情况它是一个文件夹。
#8
-3
My example:
我的例子:
const char* getFileNameFromPath(const char* path)
{
for(size_t i = strlen(path) - 1; i >= 0; i--)
{
if (path[i] == '/')
{
return &path[i+1];
}
}
return path;
}
#9
-3
@Nikolay Khilyuk offers the best solution except.
@Nikolay Khilyuk提供最佳解决方案,除了。
1) Go back to using char *, there is absolutely no good reason for using const.
1)回到使用char *,没有充分的理由使用const。
2) This code is not portable and is likely to fail on none POSIX systems where the / is not the file system delimiter depending on the compiler implementation. For some windows compilers you might want to test for '\' instead of '/'. You might even test for the system and set the delimiter based on the results.
2)此代码不可移植,并且可能在没有/不是文件系统分隔符的POSIX系统上失败,具体取决于编译器实现。对于某些Windows编译器,您可能希望测试'\'而不是'/'。您甚至可以测试系统并根据结果设置分隔符。
The function name is long but descriptive, no problem there. There is no way to ever be sure that a function will return a filename, you can only be sure that it can if the function is coded correctly, which you achieved. Though if someone uses it on a string that is not a path obviously it will fail. I would have probably named it basename, as it would convey to many programmers what its purpose was. That is just my preference though based on my bias your name is fine. As far as the length of the string this function will handle and why anyone thought that would be a point? You will unlikely deal with a path name longer than what this function can handle on an ANSI C compiler. As size_t is defined as a unsigned long int which has a range of 0 to 4,294,967,295.
函数名称很长但是描述性,没有问题。无法确定函数是否会返回文件名,只有在函数编码正确的情况下才能确定它是否可以实现。虽然如果有人在不是路径的字符串上使用它,显然会失败。我可能已经将它命名为basename,因为它会向许多程序员传达它的目的是什么。这只是我的偏好,虽然基于我的偏见,你的名字很好。至于这个函数将处理的字符串的长度以及为什么有人认为这将是一个点?您不太可能处理路径名长于此函数在ANSI C编译器上可以处理的路径名。由于size_t被定义为unsigned long int,其范围为0到4,294,967,295。
I proofed your function with the following.
我用以下方法证明了你的功能。
#include <stdio.h>
#include <string.h>
char* getFileNameFromPath(char* path);
int main(int argc, char *argv[])
{
char *fn;
fn = getFileNameFromPath(argv[0]);
printf("%s\n", fn);
return 0;
}
char* getFileNameFromPath(char* path)
{
for(size_t i = strlen(path) - 1; i; i--)
{
if (path[i] == '/')
{
return &path[i+1];
}
}
return path;
}
Worked great, though Daniel Kamil Kozar did find a 1 off error that I corrected above. The error would only show with a malformed absolute path but still the function should be able to handle bogus input. Do not listen to everyone that critiques you. Some people just like to have an opinion, even when it is not worth anything.
工作得很好,虽然Daniel Kamil Kozar确实找到了我在上面纠正过的1次错误。该错误仅显示格式错误的绝对路径,但该函数仍应能够处理虚假输入。不要听那些批评你的人。有些人只是喜欢有意见,即使它没有任何价值。
I do not like the strstr() solution as it will fail if filename is the same as a directory name in the path and yes that can and does happen especially on a POSIX system where executable files often do not have an extension, at least the first time which will mean you have to do multiple tests and searching the delimiter with strstr() is even more cumbersome as there is no way of knowing how many delimiters there might be. If you are wondering why a person would want the basename of an executable think busybox, egrep, fgrep etc...
我不喜欢strstr()解决方案,因为如果文件名与路径中的目录名相同则会失败,是的,尤其是在可执行文件通常没有扩展名的POSIX系统上会发生这种情况,至少是第一次这意味着你必须做多个测试并用strstr()搜索分隔符更加麻烦,因为无法知道可能有多少分隔符。如果你想知道为什么一个人想要一个可执行文件的基本名称认为busybox,egrep,fgrep等...
strrchar() would be cumbersome to implement as it searches for characters not strings so I do not find it nearly as viable or succinct as this solution. I stand corrected by Rad Lexus this would not be as cumbersome as I thought as strrchar() has the side effect of returning the index of the string beyond the character found.
strrchar()实现起来很麻烦,因为它搜索字符而不是字符串,所以我发现它几乎不像这个解决方案那样可行或简洁。 Rad Standus纠正了这一点,这不像我想的那样麻烦,因为strrchar()具有将字符串的索引返回到找到的字符之外的副作用。
Take Care
保重
#1
37
See char *basename(char *path)
.
请参见char * basename(char * path)。
Or run the command "man 3 basename
" on your target UNIX/POSIX system.
或者在目标UNIX / POSIX系统上运行命令“man 3 basename”。
#2
13
Use basename
(which has odd corner case semantics) or do it yourself by calling strrchr(pathname, '/')
and treating the whole string as a basename if it does not contain a '/'
character.
使用basename(具有奇数的case case语义)或者通过调用strrchr(pathname,'/')并将整个字符串视为基本名称(如果它不包含'/'字符)来自行完成。
#3
4
Here's an example of a one-liner (given char * whoami
) which illustrates the basic algorithm:
这是一个单行(给定char * whoami)的例子,它说明了基本算法:
(whoami = strrchr(argv[0], '/')) ? ++whoami : (whoami = argv[0]);
an additional check is needed if NULL is a possibility. Also note that this just points into the original string -- a "strdup()
" may be appropriate.
如果可能为NULL,则需要进行额外检查。另请注意,这只是指向原始字符串 - “strdup()”可能是合适的。
#4
1
You could use strstr
in case you are interested in the directory names too:
如果您对目录名称感兴趣,也可以使用strstr:
char *path ="ab/cde/fg.out";
char *ssc;
int l = 0;
ssc = strstr(path, "/");
do{
l = strlen(ssc) + 1;
path = &path[strlen(path)-l+2];
ssc = strstr(path, "/");
}while(ssc);
printf("%s\n", path);
#5
1
Of course if this is a Gnu/Linux only question then you could use the library functions.
当然,如果这只是一个Gnu / Linux问题,那么你可以使用库函数。
https://linux.die.net/man/3/basename
https://linux.die.net/man/3/basename
And though some may disapprove these POSIX compliant Gnu Library functions do not use const. As library utility functions rarely do. If that is important to you I guess you will have to stick to your own functionality or maybe the following will be more to your taste?
虽然有些人可能不赞成这些符合POSIX标准的Gnu库函数,但不使用const。由于库实用程序功能很少。如果这对你很重要,我想你必须坚持自己的功能,或者以下更符合你的口味?
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *fn;
char *input;
if (argc > 1)
input = argv[1];
else
input = argv[0];
/* handle trailing '/' e.g.
input == "/home/me/myprogram/" */
if (input[(strlen(input) - 1)] == '/')
input[(strlen(input) - 1)] = '\0';
(fn = strrchr(input, '/')) ? ++fn : (fn = input);
printf("%s\n", fn);
return 0;
}
#6
1
The basename()
function returns the last component of a path, which could be a folder name and not a file name. There are two versions of the basename()
function: the GNU version and the POSIX version.
basename()函数返回路径的最后一个组件,该组件可以是文件夹名称而不是文件名。 basename()函数有两个版本:GNU版本和POSIX版本。
The GNU version can be found in string.h
after you include #define _GNU_SOURCE
:
在包含#define _GNU_SOURCE之后,可以在string.h中找到GNU版本:
#define _GNU_SOURCE #include <string.h>
The GNU version uses const
and does not modify the argument.
GNU版本使用const而不修改参数。
char * basename (const char *path)
This function is overridden by the XPG (POSIX) version if libgen.h
is included.
如果包含libgen.h,则XPG(POSIX)版本会覆盖此函数。
char * basename (char *path)
This function may modify the argument by removing trailing '/' bytes. The result may be different from the GNU version in this case:
此函数可以通过删除尾随的'/'字节来修改参数。在这种情况下,结果可能与GNU版本不同:
basename("foo/bar/")
will return the string "bar" if you use the XPG version and an empty string if you use the GNU version.
如果使用XPG版本将返回字符串“bar”,如果使用GNU版本,则返回空字符串。
References:
参考文献:
-
basename (3) - Linux Man Pages
-
Function: char * basename (const char *filename), Finding Tokens in a String.
#7
0
I don't want to be nit-picking here on what other people post but...
我不想在这里发布其他人发帖但是......
- Calling some suggested "homemade" functions (such as:
getFileNameFromPath("")
) will crash the program. - 调用一些建议的“自制”函数(例如:getFileNameFromPath(“”))将使程序崩溃。
- I would recommend some caution when naming functions that inherently claims that the result will be a file.
getFilenameFromPath("/usr/local")
will return"local"
(without the quotation marks) although on a unix file system it is usually the case that it is a folder. - 我建议在命名函数时要小心,这些函数本身声称结果将是file.getFilenameFromPath(“/ usr / local”)将返回“local”(不带引号),尽管在unix文件系统上通常就是这种情况它是一个文件夹。
#8
-3
My example:
我的例子:
const char* getFileNameFromPath(const char* path)
{
for(size_t i = strlen(path) - 1; i >= 0; i--)
{
if (path[i] == '/')
{
return &path[i+1];
}
}
return path;
}
#9
-3
@Nikolay Khilyuk offers the best solution except.
@Nikolay Khilyuk提供最佳解决方案,除了。
1) Go back to using char *, there is absolutely no good reason for using const.
1)回到使用char *,没有充分的理由使用const。
2) This code is not portable and is likely to fail on none POSIX systems where the / is not the file system delimiter depending on the compiler implementation. For some windows compilers you might want to test for '\' instead of '/'. You might even test for the system and set the delimiter based on the results.
2)此代码不可移植,并且可能在没有/不是文件系统分隔符的POSIX系统上失败,具体取决于编译器实现。对于某些Windows编译器,您可能希望测试'\'而不是'/'。您甚至可以测试系统并根据结果设置分隔符。
The function name is long but descriptive, no problem there. There is no way to ever be sure that a function will return a filename, you can only be sure that it can if the function is coded correctly, which you achieved. Though if someone uses it on a string that is not a path obviously it will fail. I would have probably named it basename, as it would convey to many programmers what its purpose was. That is just my preference though based on my bias your name is fine. As far as the length of the string this function will handle and why anyone thought that would be a point? You will unlikely deal with a path name longer than what this function can handle on an ANSI C compiler. As size_t is defined as a unsigned long int which has a range of 0 to 4,294,967,295.
函数名称很长但是描述性,没有问题。无法确定函数是否会返回文件名,只有在函数编码正确的情况下才能确定它是否可以实现。虽然如果有人在不是路径的字符串上使用它,显然会失败。我可能已经将它命名为basename,因为它会向许多程序员传达它的目的是什么。这只是我的偏好,虽然基于我的偏见,你的名字很好。至于这个函数将处理的字符串的长度以及为什么有人认为这将是一个点?您不太可能处理路径名长于此函数在ANSI C编译器上可以处理的路径名。由于size_t被定义为unsigned long int,其范围为0到4,294,967,295。
I proofed your function with the following.
我用以下方法证明了你的功能。
#include <stdio.h>
#include <string.h>
char* getFileNameFromPath(char* path);
int main(int argc, char *argv[])
{
char *fn;
fn = getFileNameFromPath(argv[0]);
printf("%s\n", fn);
return 0;
}
char* getFileNameFromPath(char* path)
{
for(size_t i = strlen(path) - 1; i; i--)
{
if (path[i] == '/')
{
return &path[i+1];
}
}
return path;
}
Worked great, though Daniel Kamil Kozar did find a 1 off error that I corrected above. The error would only show with a malformed absolute path but still the function should be able to handle bogus input. Do not listen to everyone that critiques you. Some people just like to have an opinion, even when it is not worth anything.
工作得很好,虽然Daniel Kamil Kozar确实找到了我在上面纠正过的1次错误。该错误仅显示格式错误的绝对路径,但该函数仍应能够处理虚假输入。不要听那些批评你的人。有些人只是喜欢有意见,即使它没有任何价值。
I do not like the strstr() solution as it will fail if filename is the same as a directory name in the path and yes that can and does happen especially on a POSIX system where executable files often do not have an extension, at least the first time which will mean you have to do multiple tests and searching the delimiter with strstr() is even more cumbersome as there is no way of knowing how many delimiters there might be. If you are wondering why a person would want the basename of an executable think busybox, egrep, fgrep etc...
我不喜欢strstr()解决方案,因为如果文件名与路径中的目录名相同则会失败,是的,尤其是在可执行文件通常没有扩展名的POSIX系统上会发生这种情况,至少是第一次这意味着你必须做多个测试并用strstr()搜索分隔符更加麻烦,因为无法知道可能有多少分隔符。如果你想知道为什么一个人想要一个可执行文件的基本名称认为busybox,egrep,fgrep等...
strrchar() would be cumbersome to implement as it searches for characters not strings so I do not find it nearly as viable or succinct as this solution. I stand corrected by Rad Lexus this would not be as cumbersome as I thought as strrchar() has the side effect of returning the index of the string beyond the character found.
strrchar()实现起来很麻烦,因为它搜索字符而不是字符串,所以我发现它几乎不像这个解决方案那样可行或简洁。 Rad Standus纠正了这一点,这不像我想的那样麻烦,因为strrchar()具有将字符串的索引返回到找到的字符之外的副作用。
Take Care
保重