Bash:使用 set 和 eval 保留空格

作者:Mitch Frazier

如果您不太关心空格,那么 Bash 是个不错的选择:它通常会将多个空格字符转换为一个空格,并根据空格将内容分解为单词。但另一方面,如果您想保留空格,Bash 在某些时候可能会有点困难。一个经常有帮助的技巧是结合使用 Bash 的evalset命令。

假设您正在构建一个项目列表,其中每个项目可能包含重要的空格,比如类似这样的:

#!/bin/bash

items=
for i in "$@"
do
    items="$items \"$i\""
done

for i in $items
do
    echo $i
done

但是,当您运行它并尝试使用保存列表中的项目时,您并没有得到您期望的结果

  $ sh t1.sh "ab cd" "ef gh"
  "ab
  cd"
  "ef
  gh"

一种解决方案是执行以下操作

#!/bin/bash

items=
for i in "$@"
do
    items="$items \"$i\""
done

eval set -- $items
for i in "$@"
do
    echo $i
done

这会产生期望的结果

  $ sh t2.sh "ab cd" "ef gh"
  ab cd
  ef gh

重要的行是

  eval set -- $items

这个set命令获取选项之后的任何参数(此处 "--" 表示选项的结束),并将它们分配给位置参数 ($0..$n)。eval命令将其参数作为 bash 命令执行。

如果您在没有eval命令的情况下执行此操作,您将得到与第一个示例相同的结果。通过将set命令传递给evalBash,Bash 将尊重字符串中的嵌入式引号,而不是假定它们是单词的一部分。

如果您运行此脚本,您可以看到更多 Bash 正在执行的操作

#!/bin/bash

items=
for i in "$@"
do
    items="$items \"$i\""
done

set -x
set -- $items
set +x
echo '===='
set -x
eval set -- $items
set +x

这会产生

  $ sh t3.sh "ab cd" "ef gh"
  + set -- '"ab' 'cd"' '"ef' 'gh"'
  + set +x
  ====
  + eval set -- '"ab' 'cd"' '"ef' 'gh"'
  ++ set -- 'ab cd' 'ef gh'
  + set +x

Mitch Frazier 是艾默生电气公司的嵌入式系统程序员。自 2000 年代初以来,Mitch 一直是Linux Journal 的贡献者和朋友。

加载 Disqus 评论