You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

向Bash传字符串参数引发语法错误:AFNI 3dcalc fMRI数据缩放问题

解决Bash调用AFNI 3dcalc时的语法错误问题

问题背景

使用Bash脚本调用AFNI的3dcalc工具进行fMRI数据缩放,-expr参数需要传入带函数调用的表达式(含括号),提交任务时触发bash语法错误。

错误信息

-bash: -c: line 0: syntax error near unexpected token `('
-bash: -c: line 0: `apptainer run --cleanenv /Users/user44/fMRI/my_images/afni-binaries.sif 3dcalc -a /Users/user44/fMRI/PPMI/derivatives/afni_blur/sub-3102/sub-3102+tlrc.BRIK -b /Users/user44/fMRI/PPMI/derivatives/afni_scale/sub-3102/sub-3102_desc-scalestats+tlrc.BRIK -c /Users/user44/fMRI/PPMI/derivatives/fmriprep/sub-3102/func/sub-3102_task-rest_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz -expr c*min(200,a/b*100)*step(a)*step(b) -prefix /Users/user44/fMRI/PPMI/derivatives/afni_scale/sub-3102/sub-3102_task-rest_space-MNI152NLin2009cAsym_desc-preprocScaled_bold.nii '

原脚本内容

#!/bin/bash

for fn in /Users/user44/fMRI/PPMI/derivatives/fmriprep/sub*/; do
    id=$(echo $fn | cut -d '/' -f 8)
    qsub -b y -q $QUEUE_NAME -pe orte 8 -l h_vmem=8G -N $id apptainer run --cleanenv ~/fMRI/my_images/afni-binaries.sif 3dcalc \
        -a ~/fMRI/PPMI/derivatives/afni_blur/${id}/${id}+tlrc.BRIK \
        -b ~/fMRI/PPMI/derivatives/afni_scale/${id}/${id}_desc-scalestats+tlrc.BRIK \
        -c ~/fMRI/PPMI/derivatives/fmriprep/${id}/func/${id}_task-rest_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz \
        -expr "c*min(200,a/b*100)*step(a)*step(b)" \
        -prefix ~/fMRI/PPMI/derivatives/afni_scale/${id}/${id}_task-rest_space-MNI152NLin2009cAsym_desc-preprocScaled_bold.nii
    break
done

尝试过的无效写法

  • -expr "'c*min(200,a/b*100)*step(a)*step(b)'"
  • -expr "$('c*min(200,a/b*100)*step(a)*step(b)')"

问题根源

错误的核心是qsub会将整个命令作为bash -c的参数执行,原脚本中用双引号包裹的-expr表达式,在传递给qsub的过程中双引号会被bash剥离,导致表达式里的括号()暴露给bash解释器——括号在bash中是子命令/分组的语法符号,未经转义会触发语法错误。

解决方案

方式1:正确转义引号与括号

在qsub的命令行中,需要确保-expr的表达式被完整传递,不被bash解析。可以通过转义单引号或者括号实现:

转义单引号传递表达式

将表达式用单引号包裹,同时在bash中用\'转义单引号,确保qsub能完整接收:

qsub -b y -q $QUEUE_NAME -pe orte 8 -l h_vmem=8G -N $id \
  apptainer run --cleanenv ~/fMRI/my_images/afni-binaries.sif 3dcalc \
  -a ~/fMRI/PPMI/derivatives/afni_blur/${id}/${id}+tlrc.BRIK \
  -b ~/fMRI/PPMI/derivatives/afni_scale/${id}/${id}_desc-scalestats+tlrc.BRIK \
  -c ~/fMRI/PPMI/derivatives/fmriprep/${id}/func/${id}_task-rest_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz \
  -expr '\''c*min(200,a/b*100)*step(a)*step(b)'\'' \
  -prefix ~/fMRI/PPMI/derivatives/afni_scale/${id}/${id}_task-rest_space-MNI152NLin2009cAsym_desc-preprocScaled_bold.nii

转义表达式中的括号

用双引号包裹表达式,同时对每个括号加反斜杠转义:

-expr "c*min\(200,a/b*100\)*step\(a\)*step\(b\)" \

方式2:使用独立脚本(更推荐)

多层命令传递的引号转义容易出错,更可靠的方式是把3dcalc命令单独写成脚本:

  1. 创建run_3dcalc.sh脚本:
#!/bin/bash
id=$1
apptainer run --cleanenv ~/fMRI/my_images/afni-binaries.sif 3dcalc \
  -a ~/fMRI/PPMI/derivatives/afni_blur/${id}/${id}+tlrc.BRIK \
  -b ~/fMRI/PPMI/derivatives/afni_scale/${id}/${id}_desc-scalestats+tlrc.BRIK \
  -c ~/fMRI/PPMI/derivatives/fmriprep/${id}/func/${id}_task-rest_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz \
  -expr "c*min(200,a/b*100)*step(a)*step(b)" \
  -prefix ~/fMRI/PPMI/derivatives/afni_scale/${id}/${id}_task-rest_space-MNI152NLin2009cAsym_desc-preprocScaled_bold.nii
  1. 给脚本添加执行权限:
chmod +x run_3dcalc.sh
  1. 修改原循环脚本:
#!/bin/bash

for fn in /Users/user44/fMRI/PPMI/derivatives/fmriprep/sub*/; do
    id=$(echo $fn | cut -d '/' -f 8)
    qsub -b y -q $QUEUE_NAME -pe orte 8 -l h_vmem=8G -N $id ./run_3dcalc.sh $id
    break
done

这种方式彻底避免了多层命令传递的引号问题,代码更清晰易维护。

内容的提问来源于stack exchange,提问作者Connor Johnson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 08:14:54