2

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

<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 文件名”,即回显文本,出现在附加文本“form_b.xml”之前。

我查看了 dirname、basename、echo 和 tr 的手册页,但没有发现任何看起来会导致我所看到的内容的内容。我试着在谷歌上环顾四周,但我不确定我问的是正确的问题(“变量前的 bash 回显文本”?)。

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

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

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

4

3 回答 3

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"

在这里阅读

于 2012-11-01T11:29:51.467 回答
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完全忽略它),然后将to 的输出和dirnametotr的输出发送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}扩展周围是必需的。

于 2012-11-01T11:44:44.957 回答
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"
于 2012-11-01T11:33:33.620 回答