Как правильно использовать sed для удаления текста за пределами символов ""?

Итак, проблема, которую вы здесь видите, заключается в том, что цикл forрасширяется неожиданным для вас образом. Оператор диапазона {...}дает полный список всех возможных имен файлов, а не только существующих.

Например, файл 19917 не существует, поэтому появляется сообщение об ошибке mv.

Вы можете увидеть это, поместив echoв петлю:

for f in LIB008983_TRA000{19916..20167}_*_L001_R*.fastq.gz
do
  echo "$f"
done

Это дает вывод, подобный:

LIB008983_TRA00019916_*_L001_R*.fastq.gz
LIB008983_TRA00019917_*_L001_R*.fastq.gz
LIB008983_TRA00019918_*_L001_R*.fastq.gz
...
LIB008983_TRA00020078_*_L001_R*.fastq.gz
LIB008983_TRA00020079_*_L001_R*.fastq.gz
LIB008983_TRA00020080_TAAGGCGA-TATCCTCT_L001_R1.fastq.gz
LIB008983_TRA00020080_TAAGGCGA-TATCCTCT_L001_R2.fastq.gz
...
LIB008983_TRA00020084_*_L001_R*.fastq.gz
LIB008983_TRA00020085_*_L001_R*.fastq.gz
LIB008983_TRA00020086_*_L001_R*.fastq.gz

Все эти строки с *представляют несуществующие файлы.

Есть два способа решить эту проблему. Во-первых,если вы хотите сохранить диапазон, проверьтеmv:

  if [ -f "$f" ]
  then
    mv -i "$f" "$newName"
  fi

Теперь команда mvвыполняется, только если файл существует.

Второй способ — если вас не волнует диапазон, и вы просто позволяете шаблону шара совпадать:

for f in LIB008983_TRA000*_*_L001_R*.fastq.gz
do
  newName=${f/_*_\ _L001_R*.fastq.gz}
  mv -i "$f" "$newName"
done

В обоих случаях вы больше не будете пытаться mvнесуществующие файлы.

В качестве примечания; вам не нужны некоторые из ;, поэтому я удалил их из своего ответа.

У вас есть вторая проблема: ваше «$newName» не то, что вам нужно. Я кодер старой школы ksh, и могут быть выражения получше bash, но я бы сделал что-то вроде

  tail=L${f##*_L}
  head=${f%_*_$tail}_
  newName="$head$tail"
  mv -i "$f" "$newName"

Теперь, учитывая ваш список входных файлов, мы имеем

LIB008983_TRA00020080_L001_R1.fastq.gz
LIB008983_TRA00020080_L001_R2.fastq.gz
LIB008983_TRA00020081_L001_R1.fastq.gz
LIB008983_TRA00020081_L001_R2.fastq.gz
LIB008983_TRA00020082_L001_R1.fastq.gz
LIB008983_TRA00020082_L001_R2.fastq.gz
LIB008983_TRA00020083_L001_R1.fastq.gz
LIB008983_TRA00020083_L001_R2.fastq.gz
0
04.05.2020, 15:11
4 ответа

sedне просто выводит то, что находится в «правой -части» команды s. Он заменяет левое совпадение -на правое -и выводит результирующую строку (или, более технически, пространство шаблонов ).

echo 'aa"bb"aa'|sed 's/"\(.*\)"/\1/'

Оставшееся -боковое регулярное выражение соответствует "bb". Он заменяется тем, что захватила группа захвата :bb. Тогда вывод будет aabbaa.

Обратите внимание, насколько вышеприведенное отличается от

echo 'aa"bb"aa'|sed 's/.*"\(.*\)".*/\1/'

Это регулярное выражение соответствует всей строке, поэтому aa"bb"aaзаменяется на bb, что является результатом.

Другой возможный инструментawk:

echo 'aa"bb"aa'|awk -F '"' '{print $2}'

Здесь "используется в качестве разделителя, и печатается второе поле.

2
28.04.2021, 23:16

Легкая работа с cut.

Если текст поступает со стандартного ввода:

echo 'aaaaaa"bbbbb"aaaa' | cut -d\" -f2

Если текст находится в файле с именемfilename:

cut -d\" -f2 filename

Пояснение к команде cut:

  • -d\"сообщает cutчто разделитель"(\предназначен для экранирования, иначе оболочка будет жаловаться на незакрытые кавычки)
  • -f2говорит cutзахватить второе поле (, ограниченное "выше)
5
28.04.2021, 23:16

Если вам нужно решение sed, вот одно из них в сочетании сtr:

echo 'aaaaaa"bbbbb"aaaa' | tr '"' '\n' | sed -n 2p

или используйтеawk:

echo 'aaaaaa"bbbbb"aaaa' | awk -F'"' '{print $2}'

(Я бы все же предпочел cut, см. ответ @GMaster).

1
28.04.2021, 23:16

grepрешение (с использованием опережающего просмотра и, следовательно, опция PCRE):

grep -oP '(?<=")[^"]*(?=")'
1
28.04.2021, 23:16

Теги

Похожие вопросы