【问题标题】:string formatting in bashbash 中的字符串格式化
【发布时间】:2013-04-08 08:44:21
【问题描述】:

我有以下在 shell 脚本中运行的代码

foo=`seq 1 1 100`
for i in $foo; do
  echo "input$i\_now"
done

这是我的问题:在某些情况下,输出打印input1_now,而其他时候它打印input1\_now。我确定有些不同,但我不知道是什么让它以一种或另一种方式打印。如果我的代码是

for i in $foo; do
   echo "input$i_now"
done

我将始终得到input,而该行的其余部分被省略。

我知道我可以改用 input${i}_now 并让它每次都正确打印,但我最感兴趣的是了解为什么在看似相同的条件下输出会不同。

更新:

在以下示例中,第一部分正确格式化变量和文本,以便将 \_ 替换为 _。但是,最后一部分要求我将变量放在大括号中,以便它们的格式正确。

echo "Enter Simulation #: "
read sim

g.mapset results

for i in `seq 1 1 100`; do

file=sim$sim\_run$i\_sum
g.copy $file\@expSim$sim\_$i,$file

file=sim$sim\_run$i\_average
g.copy $file\@expSim$sim\_$i,$file

for year in `seq 2004 1 2006`; do   

    file=sim$sim\_$year\_run$i\_sum
    g.copy $file\@expSim$sim\_$i,$file

    file=sim$sim\_$year\_run$i\_average
    g.copy $file\@expSim$sim\_$i,$file

done

years="2004 2005 2006"
times=`seq -w 1 16 365`
runs=`seq 1 1 100`

for year in $years; do
for ptime in $times; do
    for i in $runs; do
        if [ $i -eq 1 ]; then
            g.copy  vect=sim${sim}_pts_${year}_${ptime}_run${i}@expSim${sim}_${i},sim${sim}_pts_${year}_${ptime}
        fi
        if [ $i -gt  1 ]; then  
        v.patch input=sim${sim}_pts_${year}_${ptime}_run${i}@expSim${sim}_${i} output=sim${sim}_pts_${year}_${ptime} -e -a --o
        fi
    done
done
done

【问题讨论】:

  • 它始终为我打印inputx\_now

标签: string bash


【解决方案1】:

下划线是 bash 变量名中的有效字符,因此您需要保护变量名免受周围字符的影响。

foo=`seq 1 1 100`
for i in $foo; do
  echo "input${i}_now"
done

区别:

input$i_now    # "input" + $i_now
input${i}_now  # "input" + $i + "_now"
input"$i"_now  # input + "$i" + now
input$i\_now   # input + $1 + _now - \_ "escapes" the underscore

https://man7.org/linux/man-pages/man1/bash.1.html

名称仅由字母数字字符和下划线组成且以字母字符 或下划线开头的单词。也称为标识符。

您必须通过PREFIX${braces}SUFFIXPREFIX"$quotes"SUFFIX 或通过转义 - \ - 参数名称中有效的字符来保护参数名称。所有“工作”,但我更喜欢大括号,这也是文档所指的:

要扩展的参数名称或符号可以用大括号括起来,这是可选的,但用于保护要扩展的变量免受紧随其后的字符的影响,这些字符可以解释为名称的一部分。

【讨论】:

  • 这就是为什么我需要使用input$i\_now
【解决方案2】:

_ 是否应该是有时是不同字符的占位符?

bash"input$i\_now" 和实际的_ 中总是会产生input1\_now。在双引号内,bash 仅在 $`"\ 或换行符之后删除\。见“Double Quotes” in the Bash Reference Manual。这是 POSIX 标准行为;见“Double-Quotes” in Shell Command Language

更新

如果你写"input$i_now"bash 只会打印input。它不会打印input1input1_now。这样做是因为_ 是一个有效的参数名称字符,所以bash 认为您在询问i_now 参数的值。除非您将i_now 设置为非空字符串,否则bash 会将$i_now 扩展为空字符串,从而将"input$i_now" 转换为input

更新 2

现在你已经发布了真实的代码,我们可以看看发生了什么。

首先,在您发布的真实代码中,您从未在参数扩展周围使用双引号。这会有所不同。

在双引号之外,\ 总是被删除。见“Quote Removal” in the Bash Reference Manual。因此input$i\_nowno 围绕双引号)扩展为input1_now

但是,正如我在第一次更新中解释的那样,_ 是一个参数名称字符。见“Name” in Shell Command Language。所以当bash看到input$i_now时,它把i_now作为参数名。

无论您是否使用双引号,您必须将参数名称与后面的字符分开,否则 bash 会将后面的字符视为参数名称的一部分。您可以通过在参数名称后面加上\ 来做到这一点,也可以通过将参数名称放在{...} 中来做到这一点。

始终使用{...} 更安全,因为(正如您所发现的那样?)\ 的处理方式不同,具体取决于它是否在双引号内。如果您稍后返回并添加双引号,并且您使用了\,则无论如何您都需要将\ 更改为{...}

更新 3

这里演示了\{...}和双引号的效果。首先,我们设置一些变量:

$ year=2004 ptime=1 i=1 sim=123

以下是不引用任何内容的情况:

$ echo vect=sim$sim_pts_$year_$ptime_run$i@expSim$sim_$i,sim$sim_pts_$year_$ptime
vect=sim1@expSim1,sim1

如果我们只使用{...} 而不使用双引号会发生以下情况:

$ echo vect=sim${sim}_pts_${year}_${ptime}_run${i}@expSim${sim}_${i},sim${sim}_pts_${year}_${ptime}
vect=sim123_pts_2004_1_run1@expSim123_1,sim123_pts_2004_1

如果我们添加双引号,它们没有效果:

$ echo "vect=sim${sim}_pts_${year}_${ptime}_run${i}@expSim${sim}_${i},sim${sim}_pts_${year}_${ptime}"
vect=sim123_pts_2004_1_run1@expSim123_1,sim123_pts_2004_1

如果我们只使用\,会发生以下情况:

$ echo vect=sim$sim\_pts\_$year\_$ptime\_run$i@expSim$sim\_$i,sim$sim\_pts\_$year\_$ptime
vect=sim123_pts_2004_1_run1@expSim123_1,sim123_pts_2004_1

请注意,每个 \ 都已删除。如果 \ 没有被引用,shell 会删除它。

如果我们添加双引号,它们会阻止 shell 删除每个 \

$ echo "vect=sim$sim\_pts\_$year\_$ptime\_run$i@expSim$sim\_$i,sim$sim\_pts\_$year\_$ptime"
vect=sim123\_pts\_2004\_1\_run1@expSim123\_1,sim123\_pts\_2004\_1

【讨论】:

  • 但是,在 input$i_now 的情况下,在 $i 前面时,它并不总是删除 _
  • 然后你需要编辑你的帖子以包含一个输出input1_now而不是input1\_now的可运行示例。现在你的问题基本上是“我的电脑有时很有趣。为什么?我无法提供更多细节。”
  • 如果我写 input$i_now 它将输出 input1 并省略该行的其余部分。
  • 是的。你是对的。它不打印input1,而只是打印input。但我仍然无法理解为什么input$i\_now 有时会打印input1_now 而有时会打印input1\_now。似乎不一致。我确定我在做一些不同的事情,但我看不到它。
  • @konsolebox 不。我正在编辑我的问题以添加实际代码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-22
  • 1970-01-01
相关资源
最近更新 更多