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.