【问题标题】:gnuplot for cycle and spaces in filenamegnuplot 用于文件名中的循环和空格
【发布时间】:2012-06-19 20:59:41
【问题描述】:

我在 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

【问题讨论】:

  • 不要使用seqfor ((line=0; line &lt; maxrows; line++)); do。不要使用全部大写的变量名。认为您对问题的措辞不正确,除非由于某种原因,当文件名 NOT 包含空格时,事情确实会中断。在heredoc 中没有引号删除。 "${INPUTFILES[@]}" 扩展为用双引号括起来的以空格分隔的元素列表。如果这在 gnuplot 中适用于指定文件列表,则您必须弄清楚如何转义空格。
  • @ormaaj 已解决问题。我想到了一些来自 gnuplot .. 的系统调用,比如 sed 将空格切换为破折号,然后再返回。为什么不使用 seq(可读性?!)和全大写变量名?

标签: bash filenames gnuplot


【解决方案1】:

快速回答是,您无法完全按照自己的意愿去做。 Gnuplot 在空间的迭代中拆分字符串,并且没有办法解决(AFIK)。根据您的需要,可能会有“解决方法”。您可以在 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 -- 很好的编辑。这对我来说是一个非常有趣的小挑战。谢谢
  • @mgilson,为了乐趣和完整性...一个非递归替换函数,代价是使用三个变量 (RPs,RPi,i)。 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)
【解决方案2】:

转义空格:

"data2\ with\ spaces.txt"

编辑

似乎即使使用转义序列,正如您所提到的,bash for 将始终解析空格上的输入。

您能否将您的脚本转换为以while 循环方式工作:

http://ubuntuforums.org/showthread.php?t=83424

这也可能是一个解决方案,但它对我来说是新的,我仍在使用它来了解它在做什么:

http://www.cyberciti.biz/tips/handling-filenames-with-spaces-in-bash.html

【讨论】:

  • 这没有帮助。如您所见,我的 INPUTFILES 在 ""
  • 问题出现在 gnuplot “for cycle” 评估中。 Gnuplot 根本不关心 ""。
  • 我对 bash IFS 变量很熟悉,但是这个问题是关于“gnuplot 用于循环评估”。
猜你喜欢
  • 1970-01-01
  • 2015-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-28
相关资源
最近更新 更多