在 bash 脚本上运行复杂的命令

在 bash 脚本上运行复杂的命令

我正在尝试在 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"

...在这种特殊情况下这应该不重要,但是非双引号变量引用可能会出现各种各样的问题,因此双引号通常是一个很好的做法。

答案2

您可以使用以下命令检查 bash 脚本中的常见错误外壳检查,它可以在线工作,但也可以作为离线节目。它支持不同的 shell(由 shebang 标识),并且还提供样式警告(就像在您的情况下使用$(...)而不是反引号)。您还可以实时编辑粘贴的代码并查看它的评级(与有关编码风格的普通教程结合使用很有帮助) )。

相关内容