Bash: самый короткий способ получить n-й столбец вывода

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

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

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

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

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

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

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

Ответ 1

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

cut -f2

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

Другой вариант: sed 's/.\s\+//'

Ответ 2

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

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

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

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

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

Ответ 3

Я оказался в той же ситуации и в итоге добавил эти псевдонимы в мой файл .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

Ответ 4

Попробуйте 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

удалить все файлы, указанные в первом столбце файла "файл".

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

HTH Крис

Ответ 5

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

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

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

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

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


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

Для файла file:

1 2 3
4 5 6

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

$ cat file | sh script.sh 2
2
5

Или укажите его как аргумент script:

$ sh script.sh 2 file
2
5

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

Ответ 6

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

Ответ 7

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

svn st | pick | xargs rm

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

Ответ 8

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

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

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.