Bash echo在连接字符串中间输出文本

时间:2012-11-01 11:16:23

标签: bash echo kubuntu

序言: 所以我有一个项目,我需要在一堆文件上运行转换工具。转换有多个步骤,可能需要一段时间。由于这些文件不一定在同一目录中,因此我创建了一个文件文件,其中包含要转换的文件名:

<filenames.txt>

/home/me/Documents/file1.txt
/home/me/Documents/file2.txt
/home/me/Documents/file3.txt

问题: 然后我有一个bash脚本来运行这些文件,并执行转换步骤。但是,我尝试回显相位和文件名,回声,在这种情况下,将回声文本粘贴在文件名的中间:

<script.sh>

cat filenames.txt | while read some_file
do
    echo
    echo "Begin FORMAT_A to FORMAT_B conversion..."
    echo "FORMAT_A Filename:"
    echo $some_file
    formatb_dir= dirname $some_file | tr '\n' "/"
    formatb_file= basename $some_file ".xml" | tr '\n' "_"
    formatb=$formatb_dir$formatb_file"form_b.xml\n"

    echo "FORMAT_B Filename:"
    echo $formatb
done

生成如下输出:

Begin FORMAT_A to FORMAT_B conversion...
FORMAT_A Filename:
/home/me/Documents/file1.txt
/home/me/Documents/file1.txt_FORMAT_B Filename:
form_b.xml


Begin FORMAT_A to FORMAT_B conversion...
FORMAT_A Filename:
/home/me/Documents/file2.txt
/home/me/Documents/file2.txt_FORMAT_B Filename:
form_b.xml


Begin FORMAT_A to FORMAT_B conversion...
FORMAT_A Filename:
/home/me/Documents/file3.txt
/home/me/Documents/file3.txt_FORMAT_B Filename:
form_b.xml

“FORMAT_B Filename”,echo'd文本,出现在附加文本“form_b.xml”之前。

我查看了dirname,basename,echo和tr的手册页,但我没有看到任何看起来像是因为我看到的东西。我试着在谷歌上四处看看,但我不确定我是否在问正确的问题(“bash echo text before variable”?)。

问题:为什么我的回音将回声文本放在变量的中间?

(可能相关的问题:“我是以完全错误的方式做我正在做的事情吗?”)

编辑:我接受了fortea的答案,因为它让我了解了我对变量的不了解以及从命令中获取输出。也就是说,dogbane和Jonathan Leffler表现出更好的方式来做我正在做的事情。

3 个答案:

答案 0 :(得分:2)

问题在于变量声明:

formatb_dir= dirname $some_file | tr '\n' "/"
formatb_file= basename $some_file ".xml" | tr '\n' "_"
formatb=$formatb_dir$formatb_file"form_b.xml\n"

尝试换行:echo $formatb_dir:它不包含任何内容,因为在'='之后会有一个空格。然后bash读取dirname $somefile |tr '\n' "/"并执行此命令。创建formatb_file时也一样,但这次命令是basename。 (这是“FORMAT_B文件名:”之前出现的内容)。 然后正确创建formatb,但$ formatb_dir和$ formatb_file为空,因此$ formatb将仅包含"form_b.xml\n"。 然后你回显“FORMAT_B文件名:”。 然后你回显$ formatb,它将输出“form_b.xml”。

所以,你应该使用这样的东西:

formatb_dir=$(dirname $some_file | tr '\n' "/")
formatb_file=$(basename $some_file ".xml" | tr '\n' "_")
formatb=$formatb_dir$formatb_file"form_b.xml\n"

阅读here

答案 1 :(得分:2)

问题在于您运行的命令如dirnamebasename,环境设置为奇数,而不是捕获输出。也就是说,如果你运行:

env_var=some_value commandname arg1 arg2

运行程序commandname时环境变量$env_var设置为some_value(仅适用于此命令)。在您的代码中,您写道:

formatb_dir= dirname $some_file | tr '\n' "/"

这与我给出的例子是同构的。它运行命令dirname,环境变量formatb_dir设置为空字符串(dirname完全忽略此项),然后将dirname的输出发送到tr }和tr的输出到标准输出。

  • 在shell中分配空格
  • 使用$(...)捕获输出。
  • 不要在文件名中嵌入换行符;它会让生活变得地狱!

我不打算将dirname输出末尾的换行符映射到斜杠,或将basename输出末尾的换行符映射到下划线。您可以在生成的名称中添加斜杠和下划线。

修正:

cat filenames.txt |
while read some_file
do
    echo
    echo "Begin FORMAT_A to FORMAT_B conversion..."
    echo "FORMAT_A Filename:"
    echo $some_file
    formatb_dir=$(dirname "$some_file")
    formatb_file=$(basename "$some_file" ".xml")
    formatb="${formatb_dir}/${formatb_file}_form_b.xml"
    echo "FORMAT_B Filename:"
    echo $formatb
done

formatb的分配使用${varname}两次来保持一致性;只有在${formatb_file}扩展时才需要括号。

答案 2 :(得分:1)

这是因为您正在使用tr并删除\n字符。

为什么不简单地将字符串连接在一起而不是使用tr

formatb_dir="$(dirname ${some_file})"
formatb_file="$(basename ${some_file})"
formatb="${formatb_dir}/${formatb_file}_form_b.xml"
echo "FORMAT_B Filename: $formatb"