sed :найти шаблон и заменить его другим шаблоном в той же строке

Вы также можете написать правило udev специально для этого устройства.

nano /etc/udev/rules.d/NN -Ваш _набор _из _rules.rules

# My Device which should not have admin rights
ATTRS{idVendor}=="1234", ATTRS{idProduct}=="0042", MODE="664", GROUP="plugdev"

Устройство с vid/pid :1234/0042 по-прежнему будет принадлежать пользователю root, но будет отнесено к группе «plugdev». Если ваш пользователь является членом этой группы, у вас будут права доступа к ней. Вы можете выбрать любую другую группу по вашему желанию.Режим — это двоичный код разрешений устройства. Владелец и группа могут записывать и читать, другие могут только читать устройство.

После этого вы можете запустить lsusb -vдля получения iSerial.

1
26.05.2021, 15:13
3 ответа

Следующий perl-скрипт пытается сопоставить gene, productи sprotв каждой строке ввода в указанном порядке (, т. е. отдает предпочтение гену над продуктом и продукту над побегом ). Если один из них совпадает, он извлекает слово после совпадения. Предполагается, что слово заключено в двойные -кавычки.

Если совпадение найдено, слово после gene_idзаменяется извлеченным словом.

Строка печатается независимо от того, была она изменена или нет.

#!/usr/bin/perl

while (<>) {
  my $word = '';

  if (m/\b(?:gene)\s+("[^"]*")/) {
    $word = $1;
  } elsif (m/\b(?:product)\s+("[^"]*")/) {
    $word = $1;
  } elsif (m/\b(?:sprot)\s+("[^"]*")/) {
    $word = $1;
  };

  if ($word) {
    s/\bgene_id\s+(?:"[^"]*")/gene_id $word/
  };

  print;
} 

В качестве альтернативы это можно было бы написать так, чтобы использовать цикл для перебора ключевых слов соответствия:

#!/usr/bin/perl

while (<>) {
  my $word = '';

  foreach my $match (qw(gene product sprot)) {
    if (m/\b(?:$match)\s+("[^"]*")/) {
      $word = $1;
      last; # first match wins, exit this loop
    }
  };

  if ($word) {
    s/\bgene_id\s+(?:"[^"]*")/gene_id $word/
  };

  print;
}

ИМО, эта версия лучше, потому что ее легче читать и понимать (, в частности, цикл foreachподчеркивает, что речь идет об итерации по списку слов ). Что еще более важно, это позволяет избежать повторения оператора $word = $1-, вы с меньшей вероятностью совершите ошибку, если вам нужно изменить его или добавить дополнительный код, если вам нужно сделать это только один раз, а не три раза. «Не повторяйся» не так важно в такой тривиальной маленькой программе, как эта, но может быть очень важно в больших программах. Во всяком случае, избегать/сводить к минимуму повторения — хорошая привычка программирования.

Если порядок сопоставления не был значимым (, т.е.если вам все равно, какой из них был найден, если он был ), вы можете упростить сценарий:

#!/usr/bin/perl

while (<>) {
  my ($word) = m/\b(?:gene|product|sprot)\s+("[^"]*")/;

  if ($word) {
    s/\bgene_id\s+(?:"[^"]*")/gene_id $word/
  };

  print;
} 

Независимо от того, какую версию скрипта вы используете, сохраните ее, например, как. replace.plи сделайте его исполняемым с помощью chmod +x replace.pl. Или попробуйте их все как replace1.pl, replace2.pl, replace3.pl. Затем запустите его следующим образом:

$./replace.pl input.txt 
chrM    Gnomon  CDS 8345    8513   .   +   1   gene_id "semaphorin-3F"; transcript_id "cds-XP_008824843.3"; Parent "rna-XM_008826621.3"; Dbxref "GeneID:103728653_Genbank:XP_008824843.3"; Name "XP_008824843.3"; end_range "8513,."; gbkey "CDS"; gene "semaphorin-3F"; partial "true"; product "semaphorin-3F"; protein_id "XP_008824843.3"; sprot "sp|Q13275|SEM3F_HUMAN";
chrM    StringTie   exon    2754    3700   .   +  .   gene_id "ND1"; transcript_id "cds-YP_007626758.1"; Parent "gene-ND1"; Dbxref "Genbank:YP_007626758.1,Gene "ID:15088436"; Name "YP_007626758.1"; Note "TAAstopcodoniscompletedbytheadditionof3'AresiduestothemRNA"; gbkey "CDS"; gene "ND1"; product "NADHdehydrogenasesubunit1"; protein_id "YP_007626758.1"; transl_except "(pos:3700..3700%2Caa:TERM)"; transl_table "2";
2
28.07.2021, 11:29

Чтобы завершить решение perl, вот как это можно сделать с sed. Я не уверен, как вы ожидаете, что ваш данный синтаксис будет работать, но на самом деле вам нужно регулярное выражение для соответствия строке

... gene_id "remove me"... some other stuff gene "replacement"... more stuff
    =======                                  ====
    gene_id   "[^"]*"       .*              gene    "[^"]*"

gene_idи geneсовпадают сами по себе. Строка в двойных кавычках представляет собой конкатенацию двойной кавычки, любого количества символов, не являющихся двойными кавычками ([^"]*), и еще одной двойной кавычки. Наконец-то у вас есть нечто среднее.*

Теперь вам нужно разместить \(\)вокруг деталей, которые необходимо переработать при замене:

sed 's/gene_id "[^"]*"\(.* gene \("[^"]*"\)\)/gene_id \2\1/'

Внешняя пара закрывает все, что следует оставить нетронутым. Это повторно используется как \1в замене. Внутренняя пара — это строка, которую вы хотите повторно использовать как gene_id.

Теперь, если вы хотите иметь productили sprotв качестве альтернативных замен, вы можете использовать альтернативные строки расширенных регулярных выражений:

sed -E 's/gene_id "[^"]*"(.*(gene|product|sprot) ("[^"]*"))/gene_id \3\1/'

, но это не будет предпочтительнее geneнад productнад sprot, а предпочтет последнее из присутствующих. Если вы хотите иметь такой порядок предпочтения, вам нужны отдельные шаги и начните с последнего, чтобы его можно было заменить лучшим:

sed 's/gene_id "[^"]*"\(.* sprot \("[^"]*"\)\)/gene_id \2\1/
     s/gene_id "[^"]*"\(.* product \("[^"]*"\)\)/gene_id \2\1/
     s/gene_id "[^"]*"\(.* gene \("[^"]*"\)\)/gene_id \2\1/'

Или, если приказ gene,Известно, что productи sprot `фиксированы, вы можете сначала извлечь предпочтительный идентификатор, пока фактическая строка остается в пространстве удержания:

sed -E 'h;s/(sprot|product|gene) ("[^"]*").*/#\2/;s/.*#//;G;s/(.*)\n(.*gene_id )"[^"]*"/\2\1/' 

Маркером #может быть любая строка, которая, как известно, не является частью идентификатора; для GNU sedвы можете использовать \n, чтобы быть уверенным. Таким образом, вы заменяете первую из указанных строк маркером и удаляете остальную часть строки, затем удаляете все до маркера, так что теперь в пространстве шаблона остается только идентификатор. Затем с помощью Gбудет добавлена ​​исходная строка (, которую мы сохранили в буфере удержания с помощью h), а затем идентификатор (части перед новой строкой )заменит "string"после gene_id. ]. Как-то проще написать, чем объяснить.

2
28.07.2021, 11:29

Мы используем свойство хэша, заключающееся в том, что если к заданному ключу применяется несколько значений, то последнее становится окончательным значением.

perl -lpe 'my($l,%h)=($_);
  $h{gene_id}=$_ for map {
     $l =~ /\b$_\s+(".*?");/
  } reverse qw(gene product sprot);
  s/\bgene_id\s+\K".*?";/$h{gene_id};/;
' your_file_genes

Поскольку все команды одинаковы, а меняются только имена, мы можем легко сделать управляемой всю операционную таблицу, в которой мы просто задаем имена полей, а цикл for позаботится обо всем остальном.

for i in gene product sprot;do
  cat - <<\_FMT_ |\
  sed -e "s/%s/$i/"
s/(\<gene_id\s+)"[^"]*"(.*\s%s\s+("[^"]*"))/\1\3\2/;t
_FMT_
done | sed -Ef - your_file_genes
2
28.07.2021, 11:29

Теги

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