Bash: объединенные переменные, полученные из текстового файла с использованием grep, дают неверный вывод - PullRequest
0 голосов
/ 04 июня 2019

В моем каталоге у меня есть несколько файлов nifti (например, WIP944_mp2rage-0.75iso_TR5.nii) с моего МРТ-сканера, сопровождаемые текстовыми файлами (например, WIP944_mp2rage-0.75iso_TR5_info.txt), содержащими информацию о параметрах получения (например, "Описание серии: WIP944_mp2rage- 0.75iso_TR5_INV1_PHS_ND "). На основе этих параметров (например, INV1_PHS_ND) мне нужно изменить имя файла nifti, которое отображается в $ niftibase. Я использовал grep, чтобы сделать это. Когда отображаются все переменные по отдельности, это дает мне то, что я хочу, но когда я пытаюсь объединить их в одно имя файла, переменные смешиваются вместе, а не разделяются точкой.

Я попытался использовать несколько форм sed, чтобы вырезать потенциально невидимые символы, и выявил источник проблем: часть «INV1_PHS_ND» в «описании серии» доставляет мне неприятности, которые являются компонентом $ struct, потенциально из-за Дело в том, что эта часть зависит от того, сколько полей извлекается. Иногда это 3 (в случае INV1_PHS_ND), но также может быть и 2 (INV1_ND). Когда я ввожу эту переменную в имя файла, все идет наперекосяк.

for infofile in ${PWD}/*.txt; do

  # General characteristics of subjects (i.e., date of session, group number, and subject number)
  reco=$(grep -A0 "Series description:" ${infofile} | cut -d ' ' -f 3 | cut -d '_' -f 1)
  date=$(grep -A0 "Series date:" ${infofile} | cut -c 16-21)
  group=$(grep -A0 "Subject:" ${infofile} | cut -d '^' -f 2 | cut -d '_' -f 1 )
  number=$(grep -A0 "Subject:" ${infofile} | cut -d '^' -f 2 | cut -d '_' -f 2)
  ScanNr=$(grep -A0 "Series number:" ${infofile} | cut -d ' ' -f 3)


  # Change name if reco has structural prefix
  if [[ $reco = *WIP944* ]]; then

    struct=$(grep -A0 "Series description: WIP944" ${infofile} | cut -d '_' -f 4,5,6)
    niftibase=$(basename $infofile _info.txt).nii

    #echo ${subStudy}.struct.${date}.${group}.${protocol}.${paradigm}.nii
    echo ${subStudy}.struct.${struct}.${date}.${group}.${protocol}${number}.${paradigm}.n${ScanNr}.nii

    #mv ${niftibase} ${subStudy}.struct.${struct}.${date}.${group}.${protocol}${number}.${paradigm}.n${ScanNr}.nii

  fi

done

Это дает мне вывод, как это:

.niit47.n4lot.Noc002
.niit47.n5lot.Noc002D
.niit47.n6lot.Noc002
.niit47.n8lot.Noc002
.niit47.n9lot.Noc002
.niit47.n10ot.Noc002
.niit47.n11ot.Noc002D

для всех 7 файлов WIP944. Тем не менее, это должно быть в направлении этого: H1.struct.INV2_PHS_ND.190523.Pilot.Noc001.Heat47.n11.nii, где H1, Noc и Heat47 загружаются из установочного файла.

РЕДАКТИРОВАТЬ: я пытался использовать awk следующим образом:

  reco=$(awk 'FNR==8 {print;exit}' $infofile | cut -d ' ' -f 3 | cut -d '_' -f 1)
  date=$(awk 'FNR==2 {print;exit}' $infofile | cut -c 15-21)
  group=$(awk 'FNR==6 {print;exit}' $infofile | cut -d '^' -f 2 | cut -d '_' -f 1 )
  number=$(awk 'FNR==6 {print;exit}' $infofile | cut -d '^' -f 2 | cut -d '_' -f 2)
  ScanNr=$(awk 'FNR==14 {print;exit}' $infofile | cut -d ' ' -f 3)

, который снова дал мне правильный вывод при выводе переменных по отдельности, но не при попытке их объединить: .niit47.n11022_PHS_ND.

Я использовал echo "$struct" | tr -dc '[:print:]' | od -c, чтобы увидеть, были ли скрытые символы из-за окончания строки, что привело к:

0000000    I   N   V   2   _   P   H   S   _   N   D
0000013

РЕДАКТИРОВАТЬ: Вот как выглядит текстовый файл:

Series UID: 1.3.12.2.1107.5.2.34.18923.2019052316005066316714852.0.0.0
Study date: 20190523
Study time: 153529.718000
Series date: 20190523
Series time: 160111.750000
Subject: MDC-0153,pilot_003^pilot_003
Subject birth date: 19970226
Series description: WIP944_mp2rage-0.75iso_TR5_INV1_PHS_ND
Image type: ORIGINAL\PRIMARY\P\ND
Manufacturer: SIEMENS
Model name: Investigational_Device_7T
Software version: syngo MR B17
Study id: 1
Series number: 5
Repetition time (ms): 5000
Echo time[1] (ms): 2.51
Inversion time (ms): 900
Flip angle: 7
Number of averages: 1
Slice thickness (mm): 0.75
Slice spacing (mm): 
Image columns: 320
Image rows: 320
Phase encoding direction: ROW
Voxel size x (mm): 0.75
Voxel size y (mm): 0.75
Number of volumes: 1
Number of slices: 240
Number of files: 240
Number of frames: 0
Slice duration (ms) : 0
Orientation: sag
PixelBandwidth: 248

У меня есть один из них для каждого файла nifti. subStudy жестко запрограммирован в установочном файле, который загружается до запуска цикла for. Когда я повторяю это, он показывает правильное значение. Мне нужно изменить имена нескольких файлов с определенным префиксом, которые хранятся в $ reco.

1 Ответ

0 голосов
/ 04 июня 2019

Как подтверждается в комментариях, входные файлы имеют возврат каретки DOS, которые в основном недопустимы в файлах Unix. Также следует обратить внимание на правильное цитирование.

В качестве общего пересмотра я бы порекомендовал заменить весь скрипт Bash на простой скрипт Awk, который является и более простым, и более идиоматическим.

for infofile in ./*.txt; do  # no need to use $(PWD)
   # Pre-filter with a simple grep
   grep -q '^Series description: [^ _]*WIP944' "$infofile" && continue
   # Still here? Means we want to rename
   suffix="$(awk -F : '
     BEGIN { split("Series description:Series date:Subject:Series number", f, /:/) }
     { sub(/\r/, ""); } # get rid of pesky DOS carriage return
     NR == 1 { nifbase = FILENAME; sub(/_info\.txt$/, ".nii", nifbase) }
     $1 in f { x[$1] = substring($0, length($1)+2) }
     END {
       split(x["Series description"], t, /_/); struct=t[4] "_" t[5] "_" t[6]
       split(x["Series description"], t, /_/); reco = t[1]
       date=substr(x["Series date"], 16, 5)
       split(x["Subject"], t, /\^/); split(t[2], tt, /_/); group=tt[1]
       number=tt[2]
       ScanNr=x["Series number"]
       ### FIXME: protocol and paradigm are still undefined
       print struct "." date "." group "." protocol number "." paradigm ".n" ScanNr
     }' "$infofile")"
  echo mv "$infofile" "$subStudy.struct.$suffix"
done

Это, вероятно, все еще требует некоторой настройки (по крайней мере, "протокол" и "парадигма" все еще не определены). Как только вам будет выведено правильное значение, вы можете удалить echo до mv и фактически переименовать файлы для вас.

(Возможно, еще лучше сначала протестировать копию ваших реальных файлов данных!)

...