I have an input file with multiple folders and histograms.
Some of these histograms have names that contain “EWCorr” and i need to rename them all so that they only contain “EW” instead and do so in the file so that the change persists when i read it later in my analysis program.
What is the best way to do that (ideally in pyroot) for all histograms in all (sub)folders.
<ROOT.TFile object ("input/ExportHistograms_AllVars_Unblinded.root") at 0x4401960>
<ROOT.TH1D object ("M_WZ_SRPtZ100to200_WZRest_all_theo_NLOOnlyEWCorr_Unc_rewtDY_3Z__1up") at 0x4600240>
<ROOT.TH1D object ("M_WZ_SRPtZ100to200_WZRest_all_theo_NLOOnlyEW_Unc_rewtDY_3Z__1up") at 0x4600240>
<ROOT.TObject object at 0x(nil)>
<ROOT.TObject object at 0x(nil)>
Why not using the command line tool rootmv ? it is like the unix command mv but for root files.
% rootmv -h
usage: rootmv [-h] [-c COMPRESS] [-i] [--recreate] SOURCE [SOURCE ...] DEST
Move objects from ROOT files to another
positional arguments:
SOURCE Source file
DEST Destination file
options:
-h, --help show this help message and exit
-c COMPRESS, --compress COMPRESS
change the compression settings of the destination
file (if not already existing).
-i, --interactive prompt before every removal.
--recreate recreate the destination file.
Examples:
- rootmv source.root:hist* dest.root
Move all histograms whose named starts with 'hist' from 'source.root' to 'dest.root'.
- rootmv source1.root:hist1 source2.root:hist2 dest.root
Move histograms 'hist1' from 'source1.root' and 'hist2' from 'source2.root' to 'dest.root'.
- rootmv --recreate source.root:hist dest.root
Recreate the destination file 'dest.root' and move the histogram named 'hist' from 'source.root' into it.
- rootmv -c 1 source.root:hist dest.root
Change the compression level of the destination file 'dest.root' and move the histogram named 'hist' from 'source.root' into it. For more information about compression settings of ROOT file, please look at the reference guide available on the ROOT site.
sadly it does not seem like it allows me to easily change the names if i dont know the full name at the start, right?
I have over 100 histograms and i know i can target them with something like inputfile:*NLOOnlyEWCorr* but what do i do to rename them to the equivalent but with the “Corr” removed. They all have a different prefix and postfix and i dont know how to retain that in the move/rename.
Perhaps you can treat this task as you wout treat bulk renaming of files in a directory? For this, you can use rootmv as @couet proposed as well as rootls and chain the two with the shell?
I think i got a bash script now that calls rootls to get me the names of all the histograms and i can probably iterate over that and call rootmv on each. However the issue is now that rootls does not give me the full path and i need that for rootmv
What i effectively need is something that would do
#!/usr/bin/env bash
inputfile="input/ExportHistograms_AllVars_Unblinded.root"
files=$(rootls "$inputfile:*/*/all/*all_theo_NLOOnlyEWCorr_*")
printf '%s\n' "$files" | while IFS="" read -r l; do array+=("$l"); done
for segment in $array
do
IFS=" " read -r -A line <<< "$segment"
for file in $line
do
echo "$file"
changedname=${file/EWCorr/EW}
echo "$changedname"
echo rootmv $inputfile:$file $inputfile:$changedname
done
done
With the only problem now being that $file only contains the final histogram name and not the full path. So the final rootmv (which i just echo atm) does not work because it can not find the histogram (and would put it in the wrong place anyway.
Edit:
This is the final script i am using now.
#!/usr/bin/env bash
inputfile="input/ExportHistograms_AllVars_Unblinded.root"
files=$(rootls "$inputfile:*/*/*/*_theo_NLOOnlyEWCorr_*")
printf '%s\n' "$files" | while IFS="" read -r l; do array+=("$l"); done
for segment in $array
do
IFS=" " read -r -A line <<< "$segment"
for file in $line
do
echo "$file"
changedname=${file/EWCorr/EW}
echo "$changedname"
IFS='_' read -r -A filepath <<< "$changedname"
if [[ "${filepath[2]}" = SR* ]]
then
region="${filepath[2]}"
sample="${filepath[3]}"
channel="${filepath[4]}"
else
region="${filepath[3]}"
sample="${filepath[4]}"
channel="${filepath[5]}"
fi
originalpath="$region/$sample/$channel/$file"
newpath="$region/$sample/$channel/$changedname"
echo rootmv $inputfile:$originalpath $inputfile:$newpath
rootmv $inputfile:$originalpath $inputfile:$newpath
done
done
But the only reason it works is because i can reconstruct the full path from the final histogram name. Still do not know how to do this if i could not.