![在 bash 脚本上运行复杂的命令](https://linux22.com/image/95544/%E5%9C%A8%20bash%20%E8%84%9A%E6%9C%AC%E4%B8%8A%E8%BF%90%E8%A1%8C%E5%A4%8D%E6%9D%82%E7%9A%84%E5%91%BD%E4%BB%A4.png)
我正在尝试在 bash 脚本中运行以下命令:
rm -rf `ls -t ${FOLDER}/other_folder | awk 'NR>5'`
我正在尝试类似的事情:
RM_CMD="$(rm -rf 'ls -t ${FOLDER}/other_folder | awk NR>5')"
稍后在函数中使用,我希望命令实际运行。
我尝试了几种变体,但总是失败,这里正确的方法是什么?
-编辑-
更多信息
如果我尝试类似的事情
RM_CMD="rm -rf `ls -t ${FOLDER}/other_folder | awk 'NR>5'`"
它似乎试图立即执行命令,这不是我的意图(我想存储正确的命令以供以后执行),但它获取所有正确的值,即没有空的。
-编辑2-
我尝试尽可能拆分命令,如下所示:
LS_CMD="ls -t ${FOLDER}/other_folder"
AWK_CMD="awk 'NR>5' ${LS_CMD}"
RM_CMD="rm -rf '${AWK_CMD}'"
但它给出了这个问题:
+ ssh -t user@server 'rm -rf '\''awk '\''NR>5'\'' ls -t /full/path/to/folder/other_folder'\'''
bash: 5 ls -t /full/path/to/folder/other_folder: No such file or directory
答案1
通常对于这样的问题,答案是阅读BashFAQ #50:“我试图将命令放入变量中,但复杂的情况总是失败!”。简短摘要:变量用于数据,而不是可执行代码,尝试将代码放入其中会遇到各种各样的问题。
但在这种情况下,还有另一个关键因素:您将通过 运行命令ssh
,这意味着它将被传递到远程系统作为数据,并由远程计算机上的 shell 解析为命令。这意味着将命令(作为数据)存储在脚本中的变量中(在本地计算机上)是合理的。
在我看来,您遇到的最大问题是,当您使用反引号或$( )
(并且它们不在单引号中)时,内部命令会立即执行(在本地计算机上),并且其输出存储在变量。为了避免这种情况,可以在定义变量时转义相关字符:
RM_CMD="rm -rf \$(ls -t '${FOLDER}/other_folder' | awk 'NR>5')"
请注意,我使用$( )
反引号代替,因为它通常是首选。在我看来,您在某些时候将反引号与单引号混淆了;它们看起来很相似,但效果却完全不同。$( )
本质上做同样的事情,但视觉上并不含糊。
另外,我假设${FOLDER}
是本地计算机上的一个变量,因此需要立即扩展(并且我在它周围添加了单引号,以防它包含任何空格或其他 shell 元字符);如果要通过远程 shell 扩展它,请改用\"\${FOLDER|/other_folder\"
。实际上,如果它本身包含任何单引号,则将单引号放在周围${FOLDER}
是行不通的。有一种方法可以解决这个问题,但我没有在这里打扰。
您还可以在变量赋值中使用单引号,但随后您会在命令中使用单引号时遇到麻烦awk
(没有干净的方法可以在单引号字符串中嵌套单引号)并且没有干净的方法${FOLDER}
在本地计算机上进行扩展。这些可以通过混合引用来解决,但很混乱。
最后,当您使用该变量时,应该将其括在双引号中:
ssh -t user@server "$RM_CMD"
...在这种特殊情况下这应该不重要,但是非双引号变量引用可能会出现各种各样的问题,因此双引号通常是一个很好的做法。