假设我想将以下命令存储在变量中
cd "/cygdrive/c/Program Files/"
所以我这样做
dir="cd \"/cygdrive/c/Program Files/\""
这应该存储导航到 Program Files 目录的命令,因此当我输入 $dir 时,它会带我到该目录。为了检查引号是否已正确转义,我输入
echo $dir
这让我
cd "/cygdrive/c/Program Files/"
所以一切都应该正常工作。但是,当我输入
$dir
我明白了
bash: cd: "/cygdrive/c/Program: No such file or directory
我做错了什么?我正在使用 Cygwin,但我认为这个问题通常适用于 bash。
答案1
简短回答:参见Bash常见问题解答 #050(“我试图将命令放入变量中,但复杂的情况总是失败!”)。
长答案:当 bash 解析命令时,它会在替换变量之前解析引号;它永远不会返回并重新解析变量值中的引号,因此它们最终不会做任何有用的事情。使用 echo 检查命令完全是误导,因为它会显示命令后它已被解析;如果您想查看实际正在执行的内容,可以使用set -x
shell 打印正在执行的命令,或使用printf "%q " $dir; echo
它而不是简单的 echo。
如果要存储复杂的命令(即“单词”中包含空格或其他特殊字符的命令),则需要将其放在数组中而不是简单的文本变量中,然后使用习语“${array[@]}”进行扩展,如下所示:
dir=(cd "/cygdrive/c/Program Files/")
"${dir[@]}"
现在,如果目的是要制作易于输入的简写,这显然不是可行的方法。请改用 shell 别名或函数:
alias dir='cd "/cygdrive/c/Program Files/"'
dir
或者
dir() { cd "/cygdrive/c/Program Files/"; }
dir
答案2
当 bash 扩展 时$dir
,它只对其进行分词和通配。分词产生三个单词:cd
、"/cygdrive/c/Program
和Files/"
。然后要执行的命令带有cd
两个参数;cd
它只查看其第一个参数 ,"/cygdrive/c/Program
它不是现有目录。
如果要对变量的内容执行完整的 shell 评估,请使用eval
:
eval "$dir"
请注意,你需要在 周围加上双引号$dir
,否则将首先执行分词,然后eval
将其参数与空格连接起来。这在这里可以正常工作,但总的来说会很糟糕(例如,如果文件名中有两个连续的空格)。
但是,字符串并不是存储要执行的 shell 命令的正确方法。除非您有特殊要求,否则应该使用函数:
dir () {
cd "/cygdrive/c/Program Files/"
}
如果你真的有兴趣输入$dir
切换到特定目录,而这不仅仅是一个简单的例子,从 bash 4 开始,输入shopt -s autocd
你的.bashrc
并设置
dir="/cygdrive/c/Program Files/"
之后,您只需在 shell 提示符下键入"/cygdrive/c/Program Files/"
或即可切换到该目录。您仍然需要使用双引号;如果您不喜欢这样,请使用 zsh 而不是 bash。"$dir"
$dir
答案3
通常,将命令存储在变量中不是一个好主意。这就是函数和别名的用途。
而不是
dir="cd \"/cygdrive/c/Program Files/\""
尝试以下其中之一:
dir="/cygdrive/c/Program Files"
...
cd "$dir"
或者
dir() { cd "/cygdrive/c/Program Files"; }
dir
或者
alias dir='cd "/tmp/Program Files"'
...
dir
第一种形式,将目录名称存储在变量中,意味着需要多输入一些内容,但是当您执行命令时,您会更清楚地知道您正在执行cd
。第二种形式最接近您想要完成的任务。(我在 bash 中很少使用别名;我实际上不确定它们与函数相比有什么优势。)
编辑 :
dir
对于别名或函数来说,And可能是一个不合适的名称,因为已经有一个同名的命令(它基本上是 的一个版本ls
,至少如果你有 GNU coreutils 的话)。
答案4
尝试
bash$ echo 'This is "a long" line' > mylist
bash$ echo @mylist
@mylist
bash$ cmd
c:\> c:\cygwin\bin\echo @mylist
This is a long line
更具体地说: