bash 中的字符串格式化

标签 string bash

我有以下在 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

最佳答案

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

bash 中,"input$i\_now" 与实际的 _ 将始终生成 input1\_now。在双引号内,bash 仅在 \ 后跟 $`、a "\ 或换行符。请参阅 “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\_now(没有 包围双引号)扩展为 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

关于bash 中的字符串格式化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16028677/

相关文章:

bash - 如何使用 Bash/Sed/Awk 对文件夹中的每个 gz 运行 RegExp Sub?

bash 管道防止全局变量分配

java - 每4个字符将char放入java字符串中

r - 字符串:提取想要的字符而不是删除不需要的字符

iOS拆分字符串

bash - 将命令作为输入传递给另一个命令(su、ssh、sh 等)

linux - 如何根据 awk 打印中的前缀获取字段?

python - 在 Python 3 中写入文件时,TypeError : a bytes-like object is required, 不是 'str'

string - 我不明白错误回溯给了我

string - 如何在shell中获取字符串的最后一个字符?