bash: кратчайший способ получить n-й столбец вывода - PullRequest
136 голосов
/ 06 сентября 2011

Допустим, что в течение вашего рабочего дня вы неоднократно сталкивались со следующей формой столбцового вывода какой-то команды в bash (в моем случае выполнение svn st в моем рабочем каталоге Rails):

?       changes.patch
M       app/models/superman.rb
A       app/models/superwoman.rb

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

Я использовал awk, чтобы попасть во второй столбец, например, когда я хочу удалить все файлы (не то, что это типичный случай использования :), я бы сделал:

svn st | awk '{print $2}' | xargs rm

Поскольку я часто это печатаю, возникает естественный вопрос: есть ли более короткий (а значит, круче) способ сделать это в bash?

Примечание: По сути, я задаю вопрос о командной оболочке, хотя мой конкретный пример относится к моему рабочему процессу SVN. Если вы чувствуете, что рабочий процесс глуп, и предлагаете альтернативный подход, я, вероятно, не буду вас опровергать, но другие могут это сделать, поскольку на самом деле вопрос заключается в том, как получить выходные данные команды n-го столбца в bash как можно быстрее. , Спасибо:)

Ответы [ 8 ]

96 голосов
/ 06 сентября 2011

Вы можете использовать cut для доступа ко второму полю:

cut -f2

Edit: Извините, не понял, что SVN не использует вкладки в выводе, так что это немного бесполезно. Вы можете адаптировать cut к выводу, но это немного хрупко - что-то вроде cut -c 10- будет работать, но точное значение будет зависеть от вашей настройки.

Другой вариант выглядит примерно так: sed 's/.\s\+//'

86 голосов
/ 06 сентября 2011

Чтобы выполнить то же самое, что и:

svn st | awk '{print $2}' | xargs rm

, используя только bash, который вы можете использовать:

svn st | while read a b; do rm "$b"; done

Конечно, это не короче, но немного более эффективно и обрабатываетпробелы в ваших именах файлов правильно.

27 голосов
/ 07 апреля 2017

Я оказался в той же ситуации и в итоге добавил эти псевдонимы в мой .profile файл:

alias c1="awk '{print \$1}'"
alias c2="awk '{print \$2}'"
alias c3="awk '{print \$3}'"
alias c4="awk '{print \$4}'"
alias c5="awk '{print \$5}'"
alias c6="awk '{print \$6}'"
alias c7="awk '{print \$7}'"
alias c8="awk '{print \$8}'"
alias c9="awk '{print \$9}'"

, что позволяет мне писать такие вещи:

svn st | c2 | xargs rm
15 голосов
/ 06 сентября 2011

Попробуйте Zsh.Он поддерживает псевдоним суффикса, поэтому вы можете определить X в вашем .zshrc как

alias -g X="| cut -d' ' -f2"

, тогда вы можете сделать:

cat file X

Вы можете сделать еще один шаг и определить его дляn-й столбец:

alias -g X2="| cut -d' ' -f2"
alias -g X1="| cut -d' ' -f1"
alias -g X3="| cut -d' ' -f3"

, который выведет n-й столбец файла "file".Вы можете сделать это для вывода grep или для меньшего вывода.Это очень удобно и убийственно для zsh.

Вы можете сделать еще один шаг и определить D следующим образом:

alias -g D="|xargs rm"

Теперь вы можете ввести:

cat file X1 D

для удаления всех файлов, упомянутых в первом столбце файла "file".

Если вы знаете bash, zsh не является чем-то большим, за исключением некоторых новых функций.

HTH Крис

8 голосов
/ 06 сентября 2011

Поскольку вы, кажется, незнакомы со сценариями, вот пример.

#!/bin/sh
# usage: svn st | x 2 | xargs rm
col=$1
shift
awk -v col="$col" '{print $col}' "${@--}"

Если вы сохраните это в ~/bin/x и убедитесь, что ~/bin находится в вашем PATH (теперь это то, что вы можете и должны вставить в свой .bashrc), у вас будет кратчайшая команда для общего извлечения столбца n ; х н.

Скрипт должен выполнять правильную проверку ошибок и залог, если вызывается с нечисловым аргументом или с неверным количеством аргументов и т. Д .; но расширение этой основной версии будет в блоке 102.

Возможно, вы захотите расширить скрипт, чтобы разрешить другой разделитель столбцов. Awk по умолчанию анализирует ввод в поля на пробелах; чтобы использовать другой разделитель, используйте -F ':', где : - новый разделитель. Реализация этого в качестве опции для скрипта делает его немного длиннее, поэтому я оставляю это как упражнение для читателя.


Использование

Данный файл file:

1 2 3
4 5 6

Вы можете передать его через стандартный ввод (используя бесполезный cat просто в качестве заполнителя для чего-то более полезного);

$ cat file | sh script.sh 2
2
5

Или предоставить его в качестве аргумента сценария:

$ sh script.sh 2 file
2
5

Здесь sh script.sh предполагает, что скрипт сохранен как script.sh в текущем каталоге; если вы сохраните его с более полезным именем где-нибудь в вашем PATH и отметите его как исполняемый, как в приведенных выше инструкциях, очевидно, вместо этого используйте полезное имя (а не sh).

5 голосов
/ 06 сентября 2011

Похоже, у вас уже есть решение.Чтобы упростить задачу, почему бы просто не поместить свою команду в скрипт bash (с коротким именем) и просто запустить ее вместо того, чтобы каждый раз вводить эту 'длинную' команду?

2 голосов
/ 09 января 2016

Если вы согласны с выбором столбца вручную, вы можете очень быстро использовать pick :

svn st | pick | xargs rm

Просто перейдите в любую ячейку 2-го столбца, нажмите c, а затем нажмите enter

1 голос
/ 06 сентября 2011

Обратите внимание, что путь к файлу не обязательно должен быть во втором столбце вывода svn-st.Например, если вы измените файл и измените его свойство, это будет 3-й столбец.

См. Возможные примеры вывода в:

svn help st

Пример вывода:

 M     wc/bar.c
A  +   wc/qax.c

Я предлагаю сократить первые 8 символов на:

svn st | cut -c8- | while read FILE; do echo whatever with "$FILE"; done

Если вы хотите быть на 100% уверены и иметь дело с причудливыми именами файлов, например, с пробелами в конце, вам нужно проанализировать вывод XML:

svn st --xml | grep -o 'path=".*"' | sed 's/^path="//; s/"$//'

Конечно, вы можете использовать какой-то настоящий XMLпарсер вместо grep / sed.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...