Running root macros with multiple (2+) arguments from the shell/Terminal directly from a script

I am trying to run a macro that has several arguments from a terminal through a script. The point of it all is that I want to run the macro for several input files which are in different directories while passing the values or some components of the macro arguments via the shell script arguments. Please see the detailed script below.

#!/bin/bash

# Function to check if input is a valid integer
is_number() {
    re='^[0-9]+$'
    if ! [[ $1 =~ $re ]] ; then
        echo "Error: Not a number" >&2; return 1
    else
        return 0
    fi
}

# Prompt user for input range and other parameters
echo "Please enter the required parameters for the macro execution."

# Get range from the user
read -p "Enter start 'day': " start_range
read -p "Enter end 'day': " end_range

# Validate range input
if ! is_number "$start_range" || ! is_number "$end_range" ; then
    echo "Invalid input. Please enter numeric values."
    exit 1
fi

# Get version of S1_ROFsByday
read -p "Enter the version of S1_ROFsByday list files: " s1_version

# Get the other parameters
read -p "Enter the number of events to be analysed (nEvents): " nEvents
read -p "Enter the tree name (treeName): " treeName
read -p "Enter the primary vertex code (PV): " PVID
read -p "Enter the event selection code (ES): " ESID

# Loop over the range
for i in $(seq $start_range $end_range); do
    # Construct the input and output file names
    input_file="/analysis/LambdaRecon_git_repos/dstlistFiles/dataDSTs/feb22_gen02/S1_ROFsByday_lists_${s1_version}/S1_0${I}_ROFs.list"
    output_filePath="/LambdaRecon_git_repos/Data_gen02DST_outs/stagelevel_analysis/stage2/dEdx1_PV${PVID}_ES${ESID}"
    output_file="S2_CutSel_S10${s1_version}_PV_${PVID}_ES_${ESID}_0${I}_out"
    output_file_param="${output_filePath}/${output_file}.root"

    # Construct the macro command
    macro_command="S2_LL_CutBased.C+\(\"${input_file}\", \"${output_file_param}\", ${nEvents}, \"${treeName}\", ${PVID}, ${ESID}\)"

    echo $PWD

    echo ${macro_command}

    echo "root -l -q ${macro_command} 2> \"${output_filePath}/${output_file}.strace\""

    # Run the macro with ROOT and redirect stack trace
#    root -l -q '${macro_command}' 2> \"${output_filePath}/${output_file}.strace\"
    root -l -q ${macro_command}
done

Essentially, I want to run the analysis macro over data from several days so I pass start_range = 34 and end_range = 42 which will analyse all the data (i.e. root files) in the folders for these specific days.

But the root does not execute the root -l -q ${macro_command} and throws an error. I believe, this is likely due to a problem with how the string for the root command is being constructed in the script.
If you have any suggestions or corrections will be deeply appreciated. This is kind of an urgent issue to be fixed.

Or if you have an entirely different idea to execute the program, that will also help.

What is the error?

Philippe.

PS. You could also write the whole code in C++ :slight_smile:

Warning in <TApplication::GetOptions>: macro 'S2_LL_CutBased.C not found
Warning in <TApplication::GetOptions>: macro "analysis/LambdaRecon_git_repos/Data_gen02DST_outs/stagelevel_analysis/stage2/dEdx1_PV5_ES2/S2_CutSel_S103_PV_5_ES_2_042_out.root", not found
Warning in <TApplication::GetOptions>: macro "t_cands", not found
Warning in <TApplication::GetOptions>: macro 5, not found
Warning in <TApplication::GetOptions>: macro 2)' not found

for the values of the variables:


${i} = 42
${s1_version} = 3
${PVID} = 5
${ESID} = 2
${treeName} = "t_cands"

Unfortunately. the macro is too long with few thousand lines. It runs without any error when I execute root -l -q 'S2_LL_CutBased.C+(arg1, arg2, arg3, arg4, arg5)' individually with specific variables.

It must be an issue with quotes in bash. It thinks the single quote is part of the filename. Try maybe like this, it works for me:

Do you mind showing how to do this with C++ ?

Hi ferhue,

I tried your suggestion with the following command:

root -l S2_LL_CutBased.C+(\"${input_file}\", \"${output_file_param}\", ${nEvents}, \"${treeName}\",${PVID}, ${ESID}) -b -q

I get the following error, Not sure what I am doing wrong here.

bash: /lustre/hades/user/gappager/gandharva/analysis/LambdaRecon_git_repos/lambda_recon_withkinfit/scripts/run_macros_S2.sh: line 56: syntax error near unexpected token `('
bash: /lustre/hades/user/gappager/gandharva/analysis/LambdaRecon_git_repos/lambda_recon_withkinfit/scripts/run_macros_S2.sh: line 56: `    root -l S2_LL_CutBased.C+(\"${input_file}\", \"${output_file_param}\", ${nEvents}, \"${treeName}\", ${PVID}, ${ESID}) -b -q'

Because anything goes after root are considered arguments of the command, you should put you ${macro_command} in quotes (to make it a single argument). By doing this, you can remove the escape for the parentheses
you can try:

    macro_command="S2_LL_CutBased.C+( \"${input_file}\", \"${output_file_param}\", ${nEvents}, \"${treeName}\", ${PVID}, ${ESID} )"
    root -l -q "${macro_command}"

Here is an example

my C code: (hello.C)

#include <cstdio>
#include <TFile.h>

void hello ( const char* name )
{
	printf( "hello %s\n", name );
}

my run script (run.sh)

#!/bin/bash

name=$1
command="hello.C+( \"$name\" )"
root -l -b -q "$command"

running the script:

$ ./run.sh "tony stark"

Processing hello.C+("tony stark")...
hello tony stark

if you don’t have the quotes around $command, then bash will “see” the following arguments:

  1. hello.C+("tony
  2. stark"
    which are not valid argument for root.
1 Like

Thanks @LongHoa for a detailed explanation. I tried you suggestion and the script now works as I intend it to. Cheers.

1 Like

The solution I suggested before is simpler and also works:

#!/bin/bash

root -l -b -q hello.C+( \"$1\" )

But you need to call

source run.sh

instead of

./run.sh

to avoid the error message you mentioned in the previous post.

“source” and “dot” use different shell programs, with different quote behavior. (At least on Ubuntu 22).

1 Like

Glad that I can help.