Итак, проблема, которую вы здесь видите, заключается в том, что цикл 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
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}'
Здесь "
используется в качестве разделителя, и печатается второе поле.
Легкая работа с cut
.
Если текст поступает со стандартного ввода:
echo 'aaaaaa"bbbbb"aaaa' | cut -d\" -f2
Если текст находится в файле с именемfilename
:
cut -d\" -f2 filename
Пояснение к команде cut
:
-d\"
сообщает cut
что разделитель"
(\
предназначен для экранирования, иначе оболочка будет жаловаться на незакрытые кавычки)-f2
говорит cut
захватить второе поле (, ограниченное "
выше)Если вам нужно решение sed
, вот одно из них в сочетании сtr
:
echo 'aaaaaa"bbbbb"aaaa' | tr '"' '\n' | sed -n 2p
или используйтеawk
:
echo 'aaaaaa"bbbbb"aaaa' | awk -F'"' '{print $2}'
(Я бы все же предпочел cut
, см. ответ @GMaster).
grep
решение (с использованием опережающего просмотра и, следовательно, опция PCRE):
grep -oP '(?<=")[^"]*(?=")'