2017-02-21 49 views
0

Я пытаюсь разбить много имен папок в цикле for и извлечь элемент между первым и последним подчеркиванием имени файла. Имена файлов могут выглядеть как ENCSR000AMA_HepG2_CTCF или ENCSR000ALA_endothelial_cell_of_umbilical_vein_CTCF.Сплит имя файла и получить элемент между первым и последним вложением подчеркивания

Моя проблема заключается в том, что имена папок отличаются друг у друга в общем количестве подчеркиванием, поэтому я не могу использовать что-то вроде:

IN=$d 
folderIN=(${IN//_/ }) 
tf_name=${folderIN[-1]%/*} #get last element which is the TF name 
cell_line=${folderIN[-2]%/*}; #get second last element which is the cell line 
dataset_name=${folderIN[0]%/*}; #get first element which is the dataset name 

cell_line может быть одно или несколько слов, разделенных подчеркиванием, но это ВСЕГДА между 1 и последний символ подчеркивания.

Любая помощь?

ответ

0

Просто сделать это в расширении параметра Баша на два шага ТОЛЬКО потому bash не поддерживает вложенное расширение параметра в отличии от zsh или других оболочек.

"${string%_*}" раздеть все после последнего вхождения «_» и "${tempString#*_}" раздеться все от начала до первого вхождения «_»

string="ENCSR000ALA_endothelial_cell_of_umbilical_vein_CTCF" 
tempString="${string%_*}" 
printf "%s\n" "${tempString#*_}" 
endothelial_cell_of_umbilical_vein 

Другой пример,

string="ENCSR000AMA_HepG2_CTCF" 
tempString="${string%_*}" 
printf "%s\n" "${tempString#*_}" 
HepG2 

Вы можете измените эту логику, чтобы применить к каждому из имен файлов в своей папке.

0

Может использовать регулярное выражение.

extract_words() { 
    [[ "$1" =~ ^([^_]+)_(.*)_([^_]+)$ ]] && echo "${BASH_REMATCH[2]}" 
} 

while read -r from_line 
do 
    extracted=$(extract_words "$from_line") 
    echo "$from_line" "[$extracted]" 
done < list_of_filenames.txt 

EDIT: Я переехал «извлечение» в качестве одной только функции Баша для повторного использования и легкой модификации для более сложных случаев, например:

extract_words() { 
     perl -lnE 'say $2 if /^([^_]+)_(.*)_([^_]+)$/' <<< "$1" 
} 
+0

Вам не нужна подстановка команд; просто позвольте 'extract_words' вызывать' [['command; 'BASH_REMATCH' установлен глобально, поэтому вы можете написать' extract_words '$ from_line "&& extract = $ {BASH_REMATCH [2]}'. – chepner

+0

@chepner уверен. Но только если вы используете встроенные bash regexes. Если кто-то заменяет содержимое 'extract_words', например, некоторыми' awk' или 'perl' (для более сложных сценариев), то потребуется замена команды. Как я уже писал, он предназначен для легкой модификации. (и потому что замена на самом деле вызывает функцию bash, она не болит): D – jm666

+0

Это будет проблема человека, внесшего изменения в 'extract_words'. Я не думаю, что приспосабливать будущие изменения к коду стоит накладных расходов на развилку, где это необязательно. – chepner