我正在尝试编写一个脚本来运行 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 manual,参见示例 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 "Extra arguments on command line" 得到一个错误提示我在变量使用上犯了一个错误。
#/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
最佳答案
你让事情变得比他们需要的更复杂。
任何采用两个命令行参数形式的选项(-f STRING
,或等效的 -f FILENAME
)的任何合理的 posix/gnu 兼容实用程序都应该还接受单个命令行参数 -fSTRING
。如果实用程序使用 getopt
或 getopt_long
,这是自动的。 gpsbabel
似乎没有使用标准的 posix 或 gnu 库来进行参数解析,但我相信它仍然是正确的。
显然,您的脚本希望它的参数是一个文件名列表;据推测,如果文件名包含空格,您将引用包含空格的名称:
./myscript "file 1.gpx" "file 2.gpx"
在那种情况下,您只需要通过在每个参数前添加 -f
来更改参数列表,这样参数列表实际上就变成了:
"-ffile 1.gpx" "-ffile 2.gpx"
这非常简单。我们将使用特定于 bash 的查找和替换语法,如 bash manual 中所述。 :(我强调了此解决方案使用的两个功能)
${parameter/pattern/string}
Pattern substitution. The pattern is expanded to produce a pattern just as in pathname expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string. If pattern begins with /, all matches of pattern are replaced with string. Normally only the first match is replaced. If pattern begins with #, it must match at the beginning of the expanded value of parameter. If pattern begins with %, it must match at the end of the expanded value of parameter. If string is null, matches of pattern are deleted and the / following pattern may be omitted. If parameter is @ or *, the substitution operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with @ or *, the substitution operation is applied to each member of the array in turn, and the expansion is the resultant list.
因此,"${@/#/-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
关于linux - Bash 和变量替换名称中带有空格的文件 : application for gpsbabel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25344664/