使用带有空格的路径名变量来构造新的命令变量而不破坏最终命令?

使用带有空格的路径名变量来构造新的命令变量而不破坏最终命令?

我读过很多关于 shell 引用和文件名中的空格的其他问题,这些建议似乎在这种情况下不起作用。

将带有带有转义空格的字符串的变量放入另一个变量中会在最终输出中取消转义空格。

该脚本根据用户输入和硬编码值组装命令,显示存储在变量中的命令,然后运行它:

#!/bin/bash

memory="4096"
cpus="--cpu=host --vcpus=2"
type="--os-type=linux"
variant="--os-variant=debiantesting"
graphics="--graphics spice"
network="--network bridge=vmbr0"
disk="--disk path=/dev/$chosen_vg_name/$lv_name"

#This line is the problem:
location="--cdrom /share/media/Linux\ ISO/debian11-server.iso";
 
# Run the command based on the supplied variable values:
install_cmd="virt-install -n $vm_name --memory $memory $cpus $type $variant $disk $location $graphics $network";

printf "$install_cmd\n";
$install_cmd;
exit 0;

我明白发生了什么事。将变量中的文件路径中的空格location添加到变量时不会被转义install_cmd,因此该virt-install命令认为ISO/debian11-server.iso是未知参数。

我也尝试过:

location='--cdrom /share/media/Linux ISO/debian11-server.iso';
location="--cdrom "/share/media/Linux ISO/debian11-server.iso"";
location='--cdrom /share/media/Linux\ ISO/debian11-server.iso';
location='--cdrom /share/media/Linux\\ ISO/debian11-server.iso';
location="--cdrom /share/media/Linux\\ ISO/debian11-server.iso";

location转义变量路径名中的空格的正确语法是什么仍然逃脱什么时候location添加到包含最终命令的变量?

答案1

那:

$install_cmd;

对 的内容调用 split+glob 运算符,$install_cmd并希望结果单词形成简单命令的预期参数,这几乎没有意义。

在这里,您可能希望bash在连接的部分中使用该语言构建代码,并最终告诉 shell 用 来解释它eval,这是危险的,因为很难避免命令注入漏洞。这里必须是:

  memory=4096
    cpus='--cpu=host --vcpus=2'
    type='--os-type=linux'
 variant='--os-variant=debiantesting'
graphics='--graphics spice'
 network='--network bridge=vmbr0'
    disk='--disk "path=/dev/$chosen_vg_name/$lv_name"'
location='--cdrom "/share/media/Linux ISO/debian11-server.iso"'
 
install_cmd="virt-install -n $vm_name --memory $memory $cpus $type $variant $disk $location $graphics $network"
printf >&2 'Interpreting: %s\n' "$install_cmd"
eval "(PS4='Running: '; set -o xtrace; $install_cmd)"

(看看在这种情况下如何$chosen_vg_name/$lv_name扩展eval)。

上面,我添加了一些内容Interpreting:Running:输出,以显示 shell 将解释哪些代码eval以及将运行哪些结果命令。该运行将使用某些execve("/path/to/virt-install", ["virt-install", "-n"...], environ)系统调用来完成,但是bashxtrace输出会将其呈现为某些 shell 代码,如果由 bash 解释,将导致相同的系统调用。


或者使用可以保存多个参数的变量类型来构建简单命令的参数:数组并调用由该数组的元素组成的命令:

  memory=4096
    cpus=(--cpu=host --vcpus=2)
    type=(--os-type=linux)
 variant=(--os-variant=debiantesting)
graphics=(--graphics spice)
 network=(--network bridge=vmbr0)
    disk=(--disk "path=/dev/$chosen_vg_name/$lv_name")
location=(--cdrom '/share/media/Linux ISO/debian11-server.iso')
 
install_cmd=(
  virt-install -n "$vm_name" --memory "$memory"
  "${cpus[@]}" "${type[@]}" "${variant[@]}" "${disk[@]}"
  "${location[@]}" "${graphics[@]}" "${network[@]}"
)

(PS4='Running: '; set -o xtrace; "${install_cmd[@]}")

(在那里,它们$chosen_vg_name/$lv_name在分配给数组时被扩展$disk)。

还要记住第一个参数printf格式。它不应包含可变数据。

shell 代码不存在双重解释,这避免了命令注入漏洞的风险,因此更可取。

相关内容