Gnuplot循环和文件名中的空格

4

我有一个bash脚本,通过gnuplot生成图形。只要输入文件名不包含空格,一切正常。

以下是我的脚本:

INPUTFILES=("data1.txt" "data2 with spaces.txt" "data3.txt")

...

#MAXROWS is set earlier, not relevant.


for LINE in $( seq 0 $(( MAXROWS - 1 )) );do

gnuplot << EOF
reset
set terminal png
set output "out/graf_${LINE}.png"

filenames="${INPUTFILES[@]}"

set multiplot 

plot for [file in filenames] file every ::0::${LINE} using 1:2 with line title "graf_${LINE}"

unset multiplot
EOF
done

这段代码本身是可行的,但只有在输入文件名中没有空格的情况下才能正常工作。

按照 gnuplot 的示例进行评估:

1 iteration: file=data1.txt  - CORRECT
2 iteration: file=data2  - INCORRECT
3 iteration: file=with  - INCORRECT
4 iteration: file=spaces.txt  - INCORRECT

1
不要使用 seq。使用 for ((line=0; line < maxrows; line++)); do。不要使用全大写的变量名。除非文件名不含有空格,否则你的问题表述有误。在heredoc中没有引号移除。"${INPUTFILES[@]}"会扩展为由双引号包围的以空格分隔的元素列表。如果这在gnuplot中用于指定文件列表有效,那么你需要想办法转义空格。 - ormaaj
@ormaaj 修正问题。我想到了一些来自gnuplot的系统调用..比如sed将空格转换为破折号,然后再转回来。那么为什么不使用seq(可读性?!)和全大写变量名呢? - Rob
2个回答

1
简单来说,你无法完全做到你想做的。Gnuplot在空格迭代中拆分字符串,没有绕过这一点的方法(据我所知)。根据你的需求,可能有一个“解决方法”。你可以编写一个(递归)函数,在gnuplot中用另一个字符串替换一个字符串。
#S,C & R stand for STRING, CHARS and REPLACEMENT to help this be a little more legible.
replace(S,C,R)=(strstrt(S,C)) ? \
    replace( S[:strstrt(S,C)-1].R.S[strstrt(S,C)+strlen(C):] ,C,R) : S

任何能够想出如何在没有递归的情况下完成此操作的人都将获得额外的奖励点数...
然后你的(bash)循环看起来像这样:
INPUTFILES_BEFORE=("data1.txt" "data2 with spaces.txt" "data3.txt")
INPUTFILES=()
#C style loop to avoid changing IFS -- Sorry SO doesn't like the #...
#This loop pre-processes files and changes spaces to '#_#'
for (( i=0; i < ${#INPUTFILES_BEFORE[@]}; i++)); do 
    FILE=${INPUTFILES_BEFORE[${i}]}
    INPUTFILES+=( "`echo ${FILE} | sed -e 's/ /#_#/g'`" ) #replace ' ' with '#_#'
done

该脚本用于预处理输入文件,在其中包含空格的文件名后面添加“#_#”... 最后,这是“完整”的脚本:

...

INPUTFILES_BEFORE=("data1.txt" "data2 with spaces.txt" "data3.txt")
INPUTFILES=()
for (( i=0; i < ${#INPUTFILES_BEFORE[@]}; i++)); do 
    FILE=${INPUTFILES_BEFORE[${i}]}
    INPUTFILES+=( "`echo ${FILE} | sed -e 's/ /#_#/g'`" ) #replace ' ' with '#_#'
done

for LINE in $( seq 0 $(( MAXROWS - 1 )) );do
gnuplot <<EOF
filenames="${INPUTFILES[@]}"
replace(S,C,R)=(strstrt(S,C)) ? \
        replace( S[:strstrt(S,C)-1].R.S[strstrt(S,C)+strlen(C):] , C ,R) : S
#replace '#_#' with ' ' in filenames.
plot for [file in filenames] replace(file,'#_#',' ') every ::0::${LINE} using 1:2 with line title "graf_${LINE}"

EOF
done

然而,我认为这里的要点是您不应该在文件名中使用空格 ;)


是的,就是这样。我几乎做到了不可想象的事情,并使用tmp文件(原始文件的副本,但名称没有空格)实现了解决方案 :) 谢谢! - Rob
1
@Rob -- 编辑得很好。这个对我来说是一个相当有趣的小挑战。谢谢。 - mgilson
1
@mgilson,为了好玩和完整性...这是一个非递归替换函数,代价是使用三个变量(RPsRPii)。 replaceStr(s,s1,s2) = (RPs="", RPi=1, (sum[i=1:strlen(s)] ((s[RPi:RPi+strlen(s1)-1] eq s1 ? (RPs=RPs.s2, RPi=RPi+strlen(s1)) : (RPs=RPs.s[RPi:RPi], RPi=RPi+1)), 0)), RPs) - theozh

0

这个并没有帮助。正如你看到的,我的INPUTFILES位于双引号之间。 - Rob
问题出现在gnuplot的“for循环”评估中。Gnuplot根本不关心引号。 - Rob
我熟悉bash IFS变量,但这个问题是关于“gnuplot循环评估”的。 - Rob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接