我想使用basename
来获取以换行符分隔的文件路径列表的基本名称。当 n > 2 时,它似乎有效:
$ basename `echo -e '/foo/bar \n /food/baz \n /oof/rab'`
bar
baz
rab
但是当 n = 2 时,它只输出第一行。
$ basename `echo -e '/foo/bar \n /food/baz'`
bar
为什么没有打印baz
?这是 中的错误吗basename
?这是我的平台信息:
$ uname -a
Darwin MacBook-Pro-4.local 15.6.0 Darwin Kernel Version 15.6.0: Sun Jun 4 21:43:07 PDT 2017; root:xnu-3248.70.3~1/RELEASE_X86_64 x86_64
答案1
basename
不接受路径列表(更不用说以换行符分隔的路径列表),它接受单个路径(可选择后跟要删除的后缀)。
此外,当您echo
在反引号中使用命令(如 )时,shell 会获取该命令的输出,将其拆分为由空格分隔的“单词”(通常是空格、制表符和换行符,但您可以使用 进行更改$IFS
),扩展它找到的任何通配符,并将所有这些的结果传递给另一个命令(basename
在本例中)。因此,echo
输出中的换行符被视为单词之间的更多空格,basename
根本不传递给。所以这个命令:
basename `echo -e '/foo/bar \n /food/baz \n /oof/rab'`
相当于:
basename "/foo/bar" "/food/baz" "/oof/rab"
...显然,当basename
获得三个这样的参数时,它会分别打印每个参数的基本名称。手册页basename
没有记录这种行为,所以如果有什么问题的话,那就是在这种情况下它没有给出错误。
类似地,此命令:
basename `echo -e '/foo/bar \n /food/baz'`
相当于
basename "/foo/bar" "/food/baz"
...但在这种情况下,basename
的行为是定义的并且完全不同 - 它采用第一个参数的基本名称,从其末尾删除第二个参数(如果匹配),并打印结果。“bar”不以“/food/baz”结尾,所以它只打印“bar”。
此外,echo -e
奇怪的是,它不可移植(即使在不同版本的 OS X 之间!)。下面,我使用 bash 的$' '
字符串格式来翻译转义序列。
如果要打印以换行符分隔的路径列表的基本名称,请使用循环basename
分别对每个路径运行:
while read -r filepath; do
basename "$filepath"
done <<< $'/foo/bar \n /food/baz'
或者直接使用sed
删除每行第一个“/”:
echo $'/foo/bar \n /food/baz \n /oof/rab' | sed 's@^.*/@@'
答案2
basename 有一个可选参数后缀 例如
basename include/stdio.h .h
返回"stdio"
您的第二个参数"/food/baz"
以空格分隔," \n "
被视为后缀。由于不匹配,因此"bar"
仅返回。
你可以试试
basename `echo -e '/foo/bar \n r'`
应该返回"ba"
。
答案3
不确定操作系统版本,但可能有一些不同的基本名称实用程序。我的(Mac OS 10.12.6 上的 /usr/bin/basename)在 echo 子命令中给出有关“-e”的错误,但这可能是我的 shell(tcsh)。
这对我有用:
basename /foo/bar /food/baz /oof/rab
答案4
为了补充@Gordon 的答案,basename
(和它的朋友dirname
)有时用来删除后缀。
$ basename /foo/bar.c .c
bar
这在编译或处理文件时很方便。例如:
SRC=$1
DEST=$(dirname $SRC)/$(basename $SRC .txt).csv
process ${SRC} > ${DEST}
(请注意,以上代码片段不适用于带有奇怪字符(空格、制表符或换行符)的文件)