#bash #sed
#bash #sed
Вопрос:
У меня есть этот мир кода:
cat BP.csv | while read line ; do
goterm=$(awk '{print $1}') ;
name=$(awk '{print $2}') ;
grep -w "$goterm" GOEA.csv | sed "s/$goterm/pi/g" ;
done
файл BP.csv
имеет этот формат:
GO:0008283 cell proliferation
GO:0009405 pathogenesis
GO:0010201 response to continuous far red light stimulus by the high-irradiance response system
GO:0009641 shade avoidance
пока GOEA.csv
имеет такой формат:
4577 GO:0006807 0.994 2014_06_01
4577 GO:0016788 0.989 2014_06_01
4577 GO:0043169 0.977 2014_06_01
4577 GO:0043170 0.963 2014_06_01
sed
не работает. Я хочу изменить GO:0043170
, например, на строку «pi», но это дает:
sed: -e expression #1, char 12: unterminated `s' command
Почему?
Спасибо.
Комментарии:
1. Каково значение goterm?
2. @Avinash Raj, серьезно? Разве вы не видите, что goterm — это первый столбец файла BP.csv?
3. Ick, ты ведь понимаешь, что эти две
awk
команды обе считываются изstdin
, а не из$line
переменной, верно?4. @Debasis, ты действительно об этом спрашиваешь?
5. @ams прав, поскольку ваш
awk
, в частности, выглядит неисправным. Весь скрипт может быть переписан в самом awk.
Ответ №1:
Вы запускаете свою awk
команду без ввода, попробуйте это:
cat BP.csv | while read line ; do
goterm=$(awk '{print $1}' <<< "$line") ;
name=$(awk '{print $2}' <<< "$line" ) ;
grep -w "$goterm" GOEA.csv | sed "s/$goterm/pi/g" ;
done
Комментарии:
1. 1. awk фактически выполнялся с использованием stdin, поэтому
$goterm
содержал список значений первого столбца, разделенный переводом строки, начиная со строки 2 и далее. Посколькуs
выражение тогда имело неэкранированный перевод строки в середине, sed сказал, что оно было незавершенным.2. @thatotherguy вы правы, иначе awk зависал бы в ожидании ввода.
Ответ №2:
Давайте немного почистим этот код:
while read goterm name
do
grep -w "$goterm" GOEA.csv | sed "s/$goterm/pi/g"
done < BP.cvs
Проблема в том, что ваши инструкции awk пытаются считывать данные из STDIN точно так же, как это делает ваш while
. Вы читаете из того же входного потока.
Что вы хотите сделать, так это извлечь значения из вашей строки. Я использую read
для этого. read
Инструкция использует значения в $IFS
для разделения входных данных. Обычно это пробелы, табуляции и новые строки. read
Считывает каждую переменную, которую вы вводите в строку, и последнее прочитанное значение содержит всю оставшуюся часть строки.
Таким образом:
while read line
считывает всю строку, пока:
while goterm name
приведет к разрыву строки как
goterm="GO:0008283"
name="cell proliferation"
Еще одна вещь. Когда вы используете grep
и sed
вместе, вам, вероятно, сойдет с рук просто sed
:
while read goterm name
do
sed -n "/$goterm/s/$goterm/pi/gp" GOEA.csv
done < BP.csv
Формат для команды sed является:
/lines/command/parameters/
Итак, я ищу строки с $goterm
в них, затем я заменяю $goterm
на pi
. -n
Средства не выводят строки, поскольку sed их обрабатывает, и p
средства для вывода строк, в которых была найдена замена.
Кстати, csv
как суффикс файла означает значения, разделенные запятыми, но ни один файл не выглядит так, как будто он разделен запятой. Являются ли эти вкладки разделяющими каждое поле. Если это так, вам нужно будет изменить $IFS
, чтобы это были вкладки.
Ответ №3:
Я бы реструктурировал все это примерно так:
while read goterm restofline
do
grep -w "${goterm}" GOEA.csv | sed -e "s/${goterm}/pi/g"
done < BP.csv
Для awk
всего этого нет причин, поскольку bash
read
встроенный компонент выполнит элементарное разделение полей за вас, если вы зададите ему несколько переменных. Кроме того, вы все равно не используете name
, так что это не нужно. cat
также не является необходимым.
В зависимости от вашего конкретного варианта использования даже grep
может быть ненужным, что делает внутреннюю команду простой sed -ne "s/${goterm}/pi/gp" GOEA.csv
. Если только вашей целью для grep -w
не является исключение строк, где ${goterm}
является подстрокой слова вместо целого слова…
Для справки в будущем, вставив set -x
над вашим циклом в вашем скрипте, вы увидите точные команды, которые выполняются, чтобы вы могли сравнить их с вашими ожиданиями.