我如何在 bash 脚本中获取当前工作目录名称,或者更好的是,仅获取终端命令。
pwd
给出当前工作目录的完整路径,例如 /opt/local/bin
但我只想要 bin
不需要基本名称,尤其不需要运行 pwd 的子 shell(其中 adds an extra, and expensive, fork operation); shell 可以使用 parameter expansion 在内部执行此操作:
result=${PWD##*/} # to assign to a variable
result=${result:-/} # to correct for the case where PWD=/
printf '%s\n' "${PWD##*/}" # to print to stdout
# ...more robust than echo for unusual names
# (consider a directory named -e or -n)
printf '%q\n' "${PWD##*/}" # to print to stdout, quoted for use as shell input
# ...useful to make hidden characters readable.
请注意,如果您在其他情况下应用此技术(不是 PWD
,而是其他一些包含目录名称的变量),您可能需要修剪任何尾部斜杠。下面使用 bash 的 extglob support 来处理多个斜杠:
dirname=/path/to/somewhere//
shopt -s extglob # enable +(...) glob syntax
result=${dirname%%+(/)} # trim however many trailing slashes exist
result=${result##*/} # remove everything before the last / that still remains
result=${result:-/} # correct for dirname=/ case
printf '%s\n' "$result"
或者,没有 extglob
:
dirname="/path/to/somewhere//"
result="${dirname%"${dirname##*[!/]}"}" # extglob-free multi-trailing-/ trim
result="${result##*/}" # remove everything before the last /
result=${result:-/} # correct for dirname=/ case
使用 basename
程序。对于您的情况:
% basename "$PWD"
bin
basename
程序的目的吗?除了缺少引号之外,这个答案有什么问题?
basename
确实是一个做正确事情的外部程序,但是运行 any 外部程序来完成 bash 可以仅使用内置功能开箱即用的事情是愚蠢的,无故产生性能影响(fork()
、execve()
、wait()
等)。
basename
的反对意见不适用于 dirname
,因为 dirname
具有 ${PWD##*/}
不具备的功能 - 转换不带斜杠的字符串例如,.
。因此,虽然使用 dirname
作为外部工具会产生性能开销,但它还具有有助于弥补相同开销的功能。
basename
的“效率”较低。但就开发人员的生产力而言,它可能更高效,因为与丑陋的 bash 语法相比,它更容易记住。所以,如果你还记得它,那就去吧。否则,basename
也同样有效。有没有人不得不提高 bash 脚本的“性能”并使其更有效率?
$ echo "${PWD##*/}"
echo "${PWD##*/}"
。
name=${PWD##*/}
是正确的,而 name=$(echo "${PWD##*/}")
是错误的(在不必要的低效率意义上)。
利用:
basename "$PWD"
或者
IFS=/
var=($PWD)
echo ${var[-1]}
将内部文件名分隔符 (IFS) 转回空格。
IFS=
IFS 后面有一个空格。
您可以使用密码和基本名称的组合。例如
#!/bin/bash
CURRENT=`pwd`
BASENAME=`basename "$CURRENT"`
echo "$BASENAME"
exit;
grep怎么样:
pwd | grep -o '[^/]*$'
pwd | xargs basename
没有.. 可能不是那么重要,但另一个答案更简单,跨环境更一致
basename $(pwd)
或者
echo "$(basename $(pwd))"
pwd
的输出在传递给 basename
之前是字符串拆分和全局扩展的。
basename "$(pwd)"
- 虽然与仅使用 basename "$PWD"
相比效率非常低,与使用参数扩展而不是调用 basename
相比,它本身效率低下。
这个线程很棒!这里还有一种味道:
pwd | awk -F / '{print $NF}'
我喜欢选定的答案(Charles Duffy),但如果您在符号链接目录中并且想要目标目录的名称,请小心。不幸的是,我认为它不能在单个参数扩展表达式中完成,也许我弄错了。这应该有效:
target_PWD=$(readlink -f .)
echo ${target_PWD##*/}
为了看到这一点,一个实验:
cd foo
ln -s . bar
echo ${PWD##*/}
报告“酒吧”
目录名
要显示路径的前导目录(不产生 /usr/bin/dirname 的 fork-exec):
echo ${target_PWD%/*}
这将例如转换 foo/bar/baz -> foo/bar
readlink -f
是 GNU 扩展,因此在 BSD(包括 OS X)上不可用。
echo "$PWD" | sed 's!.*/!!'
如果您使用的是 Bourne shell 或 ${PWD##*/}
不可用。
${PWD##*/}
是 POSIX sh - 每个现代 /bin/sh(包括 dash、ash 等)都支持它;要在最近的机器上击中真正的 Bourne,您需要使用稍微有点旧的 Solaris 系统。除此之外——echo "$PWD"
;省略引号会导致错误(如果目录名称包含空格、通配符等)。
令人惊讶的是,没有人提到这种只使用内置 bash 命令的替代方案:
i="$IFS";IFS='/';set -f;p=($PWD);set +f;IFS="$i";echo "${p[-1]}"
作为额外的奖励,您可以通过以下方式轻松获取父目录的名称:
[ "${#p[@]}" -gt 1 ] && echo "${p[-2]}"
这些将适用于 Bash 4.3-alpha 或更高版本。
对于像我这样的寻找骑师:
find $PWD -maxdepth 0 -printf "%f\n"
$PWD
更改为 "$PWD"
以正确处理不寻常的目录名称。
我通常在 sh 脚本中使用它
SCRIPTSRC=`readlink -f "$0" || echo "$0"`
RUN_PATH=`dirname "${SCRIPTSRC}" || echo .`
echo "Running from ${RUN_PATH}"
...
cd ${RUN_PATH}/subfolder
你可以用它来自动化事情......
readlink: illegal option -- f usage: readlink [-n] [file ...]
只需使用:
pwd | xargs basename
或者
basename "`pwd`"
xargs
formultion 效率低下且有错误,并且第二种公式调用 pwd
命令在子外壳中,而不是通过内置变量扩展检索相同的结果。
在带有正则表达式的 grep 下也可以正常工作,
>pwd | grep -o "\w*-*$"
如果您只想查看 bash 提示区域中的当前目录,您可以编辑 ~
中的 .bashrc
文件。将行中的 \w
更改为 \W
:
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
运行source ~/.bashrc
,它只会在提示区域显示目录名称。
参考:https://superuser.com/questions/60555/show-only-current-directory-name-not-full-path-on-bash-prompt
我非常喜欢使用 gbasename
,它是 GNU coreutils 的一部分。
basename
。它通常仅在 MacOS 和其他带有非 GNU 基本名称的平台上称为 gbasename
。
您可以使用 basename 实用程序从字符串中删除任何以 / 结尾的前缀和后缀(如果存在于字符串中),并在标准输出上打印结果。
$basename <path-of-directory>
以下命令将导致在 bash 脚本中打印您当前的工作目录。
pushd .
CURRENT_DIR="`cd $1; pwd`"
popd
echo $CURRENT_DIR
$1
将包含当前工作目录。 (2) pushd
和 popd
在这里没有任何作用,因为反引号内的任何内容都是在子 shell 中完成的——因此它不会影响父 shell 的开始目录。 (3) 使用 "$(cd "$1"; pwd)"
对带有空格的目录名称更具可读性和弹性。
只需删除 /
之前的任何字符(或 \
,如果您在 Windows 上)。由于比赛将变得贪婪,它将删除最后一个 /
之前的所有内容:
pwd | sed 's/.*\///g'
在您的情况下,结果符合预期:
λ a='/opt/local/bin'
λ echo $a | sed 's/.*\///g'
bin
$PWD
是内置 bash 变量的名称;所有内置变量名都大写(为了与局部变量区分开来,局部变量应始终至少有一个小写字符)。result=${PWD#*/}
不评估为/full/path/to/directory
;相反,它只去除第一个元素,使其成为path/to/directory
;使用两个#
字符使模式匹配变得贪婪,匹配尽可能多的字符。阅读答案中链接的参数扩展页面以获取更多信息。pwd
的输出并不总是与$PWD
的值相同,这是由于cd
通过符号链接、bash 是否设置了-o physical
选项等引起的复杂情况。这过去在处理自动挂载的目录时变得特别讨厌,其中记录物理路径而不是逻辑路径会产生一个路径,如果使用该路径,将允许自动挂载程序自发卸载正在使用的目录。sh
和csh
,如果你想要退格键工作,你必须阅读整个stty
手册页,我们喜欢它!”