Как быстро заменить параметр в конвейерной цепочке команд

Использовать скрипт awk :

awk '{ a[$2]+=$1 }END{ for(i in a) print a[i],i }' file
  • a[$2]+=$1-накапливаются значения для каждой группы("группа" считается уникальным значением 2-го поля, используется как индекс массива a)

Выход:

16 GeneA
4 GeneB
6 GeneC
11
20.12.2019, 10:41
8 ответов

Я столкнулся с похожей ситуацией и представил свое решение здесь на всякий случай, если это полезный паттерн.

Как только я пойму, что неоднократно меняю один фрагмент данных, который неудобно заменять в интерактивном режиме, я останавливаюсь и напишу небольшой whileцикл:

$ command-producing-multi-line-output | grep -i "needle" | wc -l
0
$ command-producing-multi-line-output | grep -i "haystack" | wc -l
0
$ while read needle; do

Стрелка вверх -к предыдущей строке command-producing-multi-line-outputи заменить "haystack"на"$needle"

command-producing-multi-line-output | grep -i "$needle" | wc -l; done
something
0
something else
0
gold
1

(заканчивается на Управление + D)

Или немного более причудливая вариация:

$ while read needle; do
printf 'For: %s\n' "$needle"
command-producing-multi-line-output | grep -i "$needle" | wc -l; done

Если я увижу будущее для этой строки команды -за пределами «сегодня», я запишу ее в функцию или скрипт.

10
27.01.2020, 19:56

Полезным псевдонимом в bashявляется

alias r='fc -s'

Команда rчасто встречается в других оболочках по умолчанию 1 и повторяет самую последнюю команду в истории. В руководстве bashэто даже упоминается как полезный псевдоним для определения:

[...]  A useful alias to use with this is ``r="fc -s"'',
so that typing ``r cc'' runs the last command beginning with
``cc'' and typing ``r'' re-executes the last command.

Это также позволит вам делать замены в тексте последней команды.

Здесь я запускаю вашу команду, затем я использую указанный выше псевдоним, чтобы заменить слово needleсловомhaystack:

$ command-producing-multi-line-output | grep -i "needle" | wc -l
bash: command-producing-multi-line-output: command not found
       0
$ r needle=haystack
command-producing-multi-line-output | grep -i "haystack" | wc -l
bash: command-producing-multi-line-output: command not found
       0

Когда я использую r needle=haystackв командной строке, оболочка распечатывает команду, которую собирается выполнить, а затем немедленно запускает ее. Как видите, оно тоже заменяет слово.

Ошибки, очевидно, связаны с тем, что у меня нет команды command-producing-multi-line-output, но в данном упражнении это не важно.


Команда fcне будет сохранена в вашей истории, но вы можете сохранить ее, создав ее как функцию оболочки, подобную этой:

fc() {
    command fc "$@"
    history -s fc "$@"   # append the given fc command to history
}

Затем вы можете сделать

$ command-producing-multi-line-output | grep -i "needle" | wc -l
bash: command-producing-multi-line-output: command not found
       0

Запустите самую последнюю команду, начинающуюся с comm, и замените needleнаr needle=haystack comm:

$ r needle=haystack comm
command-producing-multi-line-output | grep -i "haystack" | wc -l
bash: command-producing-multi-line-output: command not found
       0

Запустите самую последнюю команду, но замените haystackнаr haystack=beeswax:

$ r haystack=beeswax
fc -s needle=beeswax comm
command-producing-multi-line-output | grep -i "beeswax" | wc -l
bash: command-producing-multi-line-output: command not found
       0

Обратите внимание на двойной вызов fcв этой последней строке, сначала через наш псевдоним r, а затем через нашу функцию fc.

Очевидно, что сохранение команды fcв истории увеличивает риск случайного рекурсивного вызова fc -s.


1В zshэто встроенная -команда, в OpenBSD kshэто псевдоним по умолчанию для fc -s, в ksh93это псевдоним по умолчанию для hist -sи т. д.

8
27.01.2020, 19:56

Это точно для чего расширение истории :

$ command-producing-multi-line-output | grep -i "needle" | wc -l
...
$ ^needle^nipple
command-producing-multi-line-output | grep -i "nipple" | wc -l
...
11
27.01.2020, 19:56

OP говорит, что функция, объявленная в .bashrc, нецелесообразна, но ничто не мешает объявить ее интерактивно. Поскольку это только для текущего сеанса, подходит однобуквенное имя, например. q.

Начиная с

$ command-producing-multi-line-output | grep -i "haystack" | wc -l

нажмите Вверх;} для завершения функции измените haystackна $1, Control + aq(){Пробел на получить

q(){ command-producing-multi-line-output | grep -i "$1" | wc -l;}

, то вы можете использовать q needle, q haystack, q something. Я предпочитаю это решению whileв принятом в настоящее время ответе, поскольку оно позволяет использовать другие команды в -между поиском/подсчетом.

Для этого конкретного случая я бы фактически определил

q(){ command-producing-multi-line-output | grep -i "$@";}

, так как я, вероятно, хотел бы увидеть действительно совпадающие строки на каком-то этапе, поэтому я мог бы использовать q needle | wc -lили лучше q -c needleдля подсчета и q needleдля просмотра строк.

Поскольку определение функции будет храниться в истории bash, обычно можно перезагрузить определение, если оно потребуется в будущем сеансе.

5
27.01.2020, 19:56

Откройте соответствующий редактор, созданный для этого. По умолчанию вы можете сделать это с помощью Ctrl-xCtrl-e , хотя, если вы включили режим редактирования vi (, одним из способов является set -o vi), вы также можете использовать Escv .

Оказавшись там, используйте команду замены вашего редактора. В vi (m ), например,

:%substitute/needle/haystack/g
0
27.01.2020, 19:56

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

ARG1=needle; command-producing-multi-line-output | grep -i "${ARG1}" | wc -l

Первое присваивание устанавливает переменную окружения, которую затем можно использовать в последующих командах. Это служит параметром, который можно изменить по мере необходимости. Обратите внимание, что это установит переменную среды для жизни этой оболочки, но я обнаружил, что для быстрых конкретных команд это нормально. Для расширения переменных применяются обычные правила, например, одинарные кавычки '${ARG1}' не будут расширять переменную. Общую информацию можно найти на этом (вот один)https://www.gnu.org/software/bash/manual/html_node/Quoting.html

0
27.01.2020, 19:56

Я использую fzfдля этого.

Если вы хотите установить что-то вроде fzf, и ваш вывод обычно меньше экрана, попробуйте это:

echo | fzf -q 'shuf < /usr/share/dict/words | grep needle | head' --preview-window=up:99% --preview="eval {q}"

Когда появится вывод, наведите курсор на конец слова «игла», нажмите Ctrl -W и введите стог сена. Затем снова нажмите Ctrl -W и введите другое слово. И так далее.

Тем не менее, я бы не советовал делать это для каких-либо команд, которые изменяют систему. :-)Вы используете функцию предварительного просмотра fzfдля запуска команды, а fzf пытается запустить ее, как только что-то изменится. Например, когда вы нажмете Ctrl -W, вы увидите, что grep показывает сообщение об использовании, потому что на мгновение, пока вы не наберете первый символ слова замены, у него нет аргумента.

Я использую это так часто, что у меня есть скрипт под названием try, который в основном такой:

#!/bin/bash

export FZF_DEFAULT_COMMAND=echo
fzf -q "$*" --preview-window=up:99% --preview="eval {q}"
0
27.01.2020, 19:56

Сводка:Ctrl + RneeAlt + DhaystackEnter

Нажмите Ctrl + R , чтобы начать обратный пошаговый поиск и введите несколько символов текста, который вы хотите заменить (или другой текст очень рядом с ней )пока не появится нужная часть нужной командной строки (это не обязательно должна быть предыдущая командная строка ). Нажмите Ctrl + R для поиска предыдущего вхождения. Нажмите Ctrl + S , чтобы идти вперед, если вы зашли слишком далеко. Нажмите Backspace , если вы опечатались в символе.

Достигнув нужного места, вы можете использовать такие клавиши, как Удалить , Alt + D или Alt + Backspace для начала удаления текста вокруг курсора или просто Escape для выхода из пошагового поиска в достигнутой точке.

Нажмите Введите только после того, как закончите редактирование командной строки. Обратите внимание, что Enter во время пошагового поиска имеет обычное значение для выполнения текущей командной строки как она есть :это не просто выход из режима поиска (нажмите Escape , чтобы просто выйти из режима поиска ).

4
27.01.2020, 19:56

Теги

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