想象一下我当前的工作目录中有两个文件夹:back/
和front/
。我试图进入他们每个人的内心并做一些事情。从下面的简单脚本:
for dir in */ ; do
echo "$(dir)"
done
我期待这样的输出:
back
front
然而,我得到的是:
back front
back front
我不明白。结果是,如果我尝试cd
进入该文件夹:
for dir in */ ; do
echo "$(dir)"
cd $(dir)
echo "$(pwd)"
cd ..
done
我得到:
back front
/path/to/back
back front
/path/to/back
即我从不进入front/
。有人可以帮助我理解我做错了什么吗?
答案1
在类似 POSIX 的 shell 中,$(cmd)
语法是命令替换,扩展为减去尾随换行符$(cmd)
的输出。cmd
你想要的是参数扩展:$dir
或${dir}
(此处参数为dir
多变的)。
pwd
( p
rint w
orking d
ictory) 是输出 1 特殊变量内容的命令,$PWD
该变量本身包含当前工作目录的路径,因此只要不以换行符结尾,$(pwd)
就会扩展为相同的内容。$PWD
$PWD
所以你要:
for dir in */; do
(
printf '%s\n' "$dir"
cd -- "$dir" &&
printf '%s\n' "$PWD"
)
done
或者:
for dir in */; do
(
printf '%s\n' "$dir"
cd -- "$dir" &&
pwd
)
done
还请记住
echo
不能用于输出任意数据,请printf
改为使用- 您通常应该检查命令的退出状态。这里不检查 的输出
cd
意味着cd ..
如果第一个失败,接下来的操作会将您带到错误的位置cd
。 cd
最好在子 shell 中运行(使用(...)
)而不是使用,cd ..
因为后者并不总是保证让您回到初始位置(如果涉及符号链接和/或某些路径组件已在间隔中重命名)--
当不能保证非选项不以开头-
(或者+
对于某些命令来说也可能是一个问题)时,必须使用 来将选项与非选项分开。- 在类似 POSIX 的 shell 中,参数扩展和命令替换(以及算术扩展)必须用引号引起来,否则它们会经历您通常不希望的隐式 split+glob(zsh 除外)。
另请注意,在 bash(以及除 zsh 之外的其他 POSIX shell)中,当 glob 与任何文件都不匹配时,它不会展开。
因此如果当前工作目录不包含任何可以确定为类型的非隐藏文件目录,*/
全局模式只会扩展到自身*/
而不是空列表,您可能会看到一个错误,因为cd
它无法进入该*/
目录。
在 中zsh
,您可以使用N
glob 限定符for dir in */(N); do...
(或for dir in *(N-/); do...
避免$dir
以 结尾/
)。
在 ksh93 中:for dir in ~(N)*/; do...
.
在 中bash
,您可以nullglob
暂时全局设置该选项:
shopt -s nullglob
for dir in */; do
...
done
shopt -u nullglob
为了完整起见,$(var)
语法为宏Makefile
命令使用的 s中的扩展make
。
在该awk
语言中,$
是取消引用字段的一元运算符,您只需用来var
引用awk
变量。因此,将与or$(var)
相同并扩展到第th字段(如果为 0,则扩展到整个记录)。$var
$ var
var
var
在rc
-like shell 中,与, , ,$(var)
相同也可以工作,因为这是传递给 的一个元素的列表,因此您取消引用该变量,尽管您通常只使用.$var
$ var
$ 'var'
$ ( 'var' )
$
var
$var
在 TCL 中,$(var)
将扩展为键名称为空的数组变量的值var
:
$ tclsh
% array set {} {foo 1 bar 2}
% puts $(foo)
1
是的,如果在这种情况下, P
rintP
没有多大意义。你可以猜到pwd
命令(来自 70 年代中期的 Unix V5)是第一个,$PWD
并且逻辑的POSIX 指定的当前工作目录的处理是后来出现的(在 80 年代初的 ksh 中,其中实际上是(是的,缺少和引号!)pwd
的别名,并且在文档中被缩写为resent orking ictory)。有一个(当前orking目录)变量用于相同目的print - $PWD
-r
$PWD
P
W
D
tcsh
$cwd
c
w
d