-
Notifications
You must be signed in to change notification settings - Fork 2
/
add-intended-for
executable file
·119 lines (102 loc) · 3.61 KB
/
add-intended-for
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/env bash
#
# 20221020WF - init. lncd "habit" project
# 20231110WF - into lncdtools
# 20231221WF - takes multiple patterns
#
usage(){
cat <<HEREDOC
'add-intended-for' adds an element like
'IntendedFor': ['sub-1/ses-1/func/sub-1_ses-1_task-rest_bold.nii.gz']
to the json files matching \`-fmap 'pattern.json'\`
IntendedFor is used by fmriprep's susceptibility distortion correction (SDC).
USAGE:
$(basename "$0") -fmap '*PA_run-1_epi.json' [-for '*_bold.nii.gz'] [-for '*dwi.nii.gz'] subj-1/ses-1/ [subj-2/ses-1/ ...]
OPTIONS:
-help this message
-fmap pattern to find fmap json file. where to insert IntendedFor
-for pattern to find bold or dwi file(s).
default is '*_bold.nii.gz'. An alternative: '*dwi.nii.gz'
Can repeat "-for 'pattern.nii.gz'"
to put multiple patterns into the 'IntendedFor' array
-me_okay include multiecho files in search.
default is to exclude all files matching '*echo-*'
sesdir any number of session dirs
each should be session root dir with fmap/, func/ +/- dwi/
repeat for as many sessions as needed. Consider using a glob
NOTE:
* skips files where 'IntendedFor' already exists
* test with 'DRYRUN=1 add-intended-for ...'
HEREDOC
}
#shellcheck disable=SC2089 # intentionally not an array
FIND_EXCLUDE=" -not -name *echo-*"
csv_niifiles(){
local sesdir="$1"; shift
#local boldpat="${1:?need at least one bold or dwi file pattern}"
local find_names
# build a list of acceptable names
find_names=$(printf " -iname %s -or" "$@"|sed 's/-or$//')
# shellcheck disable=SC2086,SC2090 # sending multiple args in ea. var
(cd "$sesdir" &&
find func/ dwi/ \( $find_names \) $FIND_EXCLUDE ) |
sed 's/^\|$/"/g'|
paste -sd,
}
find_se_file(){
local sesdir="${1:?find_se_file requires session dir}"
local pattern="${2:?find_se_file requires a json pattern}"
mapfile -t sefiles < <(find "$sesdir/fmap" -name "$pattern")
if [[ -z "${sefiles[*]}" || ! -r "${sefiles[0]}" ]]; then
warn "no like '$sesdir/fmap/$pattern'?"
exit 1
fi
[ ${#sefiles[@]} -gt 1 ] && warn ">1 match for '$pattern' found: ${sefiles[*]}"
printf "%s\n" "${sefiles[@]}"
}
add_intended_for(){
local sefile forfilescsv str
sefile="$1"; shift
forfilescsv="$1"; shift
# (DANGER) inline replace on
# matching files without an 'IntendedFor' line
str="\"IntendedFor\": [$forfilescsv],"
grep -L IntendedFor "$sefile" |
xargs -r dryrun sed "s;{;{\n$str;" -i || :
return 0
}
_intendedFor() {
local boldpatt=()
local sepatt=""
local sesdirs=()
[ $# -eq 0 ] && usage && exit 1
while [ $# -gt 0 ]; do
case "$1" in
-for|-bold|-dwi) boldpatt=("${boldpatt[@]}" "$2"); shift 2;;
-fmap) sepatt="$2"; shift 2;;
-me_okay) FIND_EXCLUDE=""; shift 1;;
-help) usage; exit 0;;
*) sesdirs+=("$1"); shift 1;;
esac
done
[ -z "${boldpatt[*]}" ] && boldpatt=('*_bold.nii.gz')
# check inputs
[ -z "$sepatt" ] &&
echo "ERROR: no -fmap pattern; see -help" &&
exit 1
! [[ "$sepatt" =~ .json$ ]] &&
echo "-fmap pattern must end with .json" &&
exit 2
for sesdir in "${sesdirs[@]}"; do
mapfile -t sefiles < <(find_se_file "$sesdir" "$sepatt")
for sefile in "${sefiles[@]}"; do
forfilescsv=$(csv_niifiles "$sesdir" "${boldpatt[@]}")
[ -z "$forfilescsv" ] &&
warn "no matching files in $sesdir/{func,dwi}/ matching ${boldpatt[*]}" && return 1
add_intended_for "$sefile" "$forfilescsv" || :
done
done
return 0
}
# if not sourced (testing), run as command
eval "$(iffmain "_intendedFor")"