[英]Bash and Variable Substitution for file with space in their name: application for gpsbabel
我正在尝试编写脚本以运行gpsbabel。 我陷于处理名称包含(空格)的文件。 我的问题是在bash语法中。 bash程序员的任何帮助或见解将不胜感激。
gpsbabel是允许合并gps设备记录的曲目的软件。
对于我而言,可以正常工作的语法是:
gpsbabel -i gpx -f "file 1.gpx" -f "file 2.gpx" -o gpx -F output.gpx -x track,merge
GPS数据的输入格式由-i给出,输出格式由-o给出 。 输入数据文件在-f之后列出,结果文件在-F之后
(请参阅gpsbabel手册 ,请参见示例4.9)
我正在尝试编写一批批处理,以使用最初不知道的许多输入文件来运行此语法。 这意味着必须对从批处理参数传递的每个输入文件重复序列-f“ name_of_the_input_file” 。
这是一个脚本,用于文件名中没有空格的文件
#!/bin/bash
# Append multiple gpx files easily
# batch name merge_gpx.sh
# Usage:
# merge_gpx.sh track_*.gpx
gpsbabel -i gpx $(echo $* | for GPX; do echo -n " -f $GPX "; done) \
-o gpx -F appended.gpx
`因此,我试图修改此脚本以处理包含空格的文件名。 我迷上了bash替代,写了更多的bash用于调试目的,但没有成功。
这是我的审判之一
我从gpsbabel “命令行上的额外参数”收到错误消息,提示我在变量用法上犯了一个错误。
#/bin/bash
# Merging all tracks in a single one
old_IFS=$IFS # Backup internal separator
IFS=$'\n' # New IFS
let i=0
echo " Merging GPX files"
for file in $(ls -1 "$@")
do
let i++
echo "i=" $i "," "$file"
tGPX[$i]=$file
done
IFS=$old_IFS #
#
echo "Number of files:" ${#tGPX[@]}
echo
# List of the datafile to treat (each name protected with a ')
LISTE=$(for (( ifile=1; ifile<=${#tGPX[@]} ; ifile++)) ;do echo -ne " -f '""${tGPX[$ifile]}""'"; done)
echo "LISTE: " $(echo -n $LISTE)
echo "++Merging .."
if (( $i>=1 )); then
gpsbabel -t \
-i gpx $(echo -n $LISTE) \
-x track,merge,title="TEST COMPIL" \
-o gpx -F track_compil.gpx
else
echo "Wrong selection of input file"
fi
#end
使用数组:
files=()
for f; do
files+=(-f "$f")
done
gpsbabel -i gpx "${files[@]}" -o gpx -F appended.gpx
for f; do
for f; do
是for f in "$@"; do
缩写for f in "$@"; do
for f in "$@"; do
; 大多数情况下,您想使用$@
而不是$*
来访问命令行参数。 引用"${files[@]}"
会产生一个单词列表,每个元素一个,就好像被引用一样,因此将包含空格的数组元素视为一个单词。
您使自己的事情变得复杂得多。
任何合理的posix / gnu兼容实用程序,它采用两个命令行参数( -f STRING
或等效的-f FILENAME
)形式的选项,也应接受单个命令行参数-fSTRING
。 如果该实用程序使用getopt
或getopt_long
,则这是自动的。 gpsbabel
似乎没有使用标准的posix或gnu库进行参数解析,但我相信它仍然可以解决这个问题。
显然,您的脚本希望其参数为文件名列表; 大概,如果文件名包含空格,您将引用包含空格的名称:
./myscript "file 1.gpx" "file 2.gpx"
在这种情况下,您只需要在参数列表前加上-f
即可更改参数列表,从而使参数列表生效:
"-ffile 1.gpx" "-ffile 2.gpx"
这非常简单。 我们将使用bash手册中介绍的bash特定的查找和替换语法:(我着重介绍了此解决方案使用的两个功能)
${parameter/pattern/string}
模式替换。 与路径名扩展一样,扩展模式以产生模式。 扩展参数,并将模式与其值的最长匹配项替换为字符串。 如果pattern以/开头,则pattern的所有匹配项都将替换为字符串。 通常只替换第一个比赛。 如果pattern以#开头,则它必须与参数的扩展值的开头匹配。 如果pattern以%开头,则它必须在参数的扩展值的末尾匹配。 如果string为null,则删除模式匹配项,并且/后面的模式可以省略。 如果parameter为@或* ,则将替换操作依次应用于每个位置参数,并且扩展为结果列表。 如果parameter是用@或*下标的数组变量,则将替换操作依次应用于数组的每个成员,并且扩展为结果列表。
因此, "${@/#/-f}"
是参数列表( @ ),在开头( # )处的空模式被-f
替换:
#/bin/bash
# Merging all tracks in a single one
# $# is the number of arguments to the script.
if (( $# > 0 )); then
gpsbabel -t \
-i gpx "${@/#/-f}" \
-x track,merge,title="TEST COMPIL" \
-o gpx -F track_compil.gpx
else
# I changed the error message to make it more clear, sent it to stderr
# and cause the script to fail.
echo "No input files specified" >> /dev/stderr
exit 1
fi
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.