bash: найкоротший спосіб отримати n-й стовпчик випуску


166

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

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

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

Те, що я робив, - це використовувати awkдля отримання другого стовпця, наприклад, коли я хочу видалити всі файли (не те, що це типовий шрифт :), я би зробив:

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

Оскільки я багато набираю це, природним є питання: чи існує коротший (таким чином крутіший) спосіб досягти цього в баші?

ПРИМІТКА. Те, що я задаю, - це по суті питання командної оболонки, навіть якщо мій конкретний приклад є на моєму робочому процесі svn. Якщо ви вважаєте, що робочий процес нерозумний і пропонуєте альтернативний підхід, я, мабуть, не буду вас голосувати, але інші можуть, оскільки питання тут справді полягає в тому, як отримати виведення команди n-го стовпчика в bash, в найкоротші терміни . Дякую :)


1
Коли ви часто використовуєте команду, вам краще створити скрипт і поставити його на свій шлях. Ви можете просто створити функцію у вашому bashrc, якщо вам більше подобається. Я не бачу сенсу зменшити вираз вибору стовпця.
Лінч

1
Ви маєте рацію, і я можу це зробити. «Точка» - це пошук нових способів робити речі на башті, з метою навчання, але переважно для розваги :)
Sv1

1
Крім того, у вас немає свого .bashrc, коли десь ssh-ing, тому корисно знати, як обходитися без нього.
Кос

Відповіді:


125

Ви можете використовувати cutдля доступу до другого поля:

cut -f2

Редагувати: Вибачте, не зрозумів, що SVN не використовує вкладки у своєму виході, тому це трохи марно. Ви можете cutналаштувати вихід, але це трохи крихко - щось на кшталт cut -c 10- буде працювати, але точне значення буде залежати від вашої установки.

Ще один варіант: sed 's/.\s\+//'


1
Спробуйте використовувати cut -f2з svn stвиходом. Ви побачите, що це не працює.
Лінч

Я припускав, що реальні svn stбудуть використовувати вкладки у своєму виході. Після деяких тестувань здається, що це не так. Блін.
porges

21
Проходження відповідного роздільника, щоб -dце могло працювати.
Йог

6
Щоб розширити те, що сказав @Yogh, пробіли як роздільник, це виглядатиме так cut -d" " -f2.
adamyonk

W / o awk на stdout використовувати xargs: svn st | xargs | вирізати -d "" -f2
vr286

106

Зробити те саме, що:

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

використовуючи лише bash, ви можете використовувати:

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

Зрозуміло, це не коротше, але трохи ефективніше і правильно обробляє пробіли у ваших іменах.


Що таке aі bяк їх отримати?
Тимо

1
@Timo aпредставляє перший стовпець і bпредставляє решту стовпців. Якщо ви хочете надрукувати другий стовпець, використовуйте, read a b c;а потім використовуйте echoзамість rm. Я використовував це, щоб отримати безліч процесів ідентифікаторів, які слідували за схемою grep, щоб я міг їх перервати.
Метт Клейнсміт

36

Я опинився в тій же самій ситуації і закінчив додавати ці псевдоніми у свій .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
Функції Bash, як правило, більш корисні. Я зробив це: function c() { awk "{print \$$1}" } Тоді ви можете зробити: svn st | c 2 | xargs rm
Aissen

8
Але тоді мені потрібно набрати додатковий простір. Це занадто виснажливо :)
StackedCrooked

16

Спробуйте 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-й стовпчик файлу "файл". Ви можете зробити це і для греп-виходу, або для меншого виходу. Це дуже зручно і вбивча риса zsh.

Ви можете піти ще на крок і визначити D таким:

alias -g D="|xargs rm"

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

cat file X1 D

видалити всі файли, згадані в першому стовпці файла "файл".

Якщо ви знаєте bash, zsh не зміниться, крім деяких нових функцій.

HTH Chris


ах, я бачу, що ви оновили свою відповідь, коли я надрукував свій коментар вище :) Чи можете ви якось динамічно вказати, який стовпець отримати, чи мені потрібні n-рядки в моєму .zshrc (не те, що важливо, просто цікаво)
Sv1

Далі я відредагував свою публікацію та визначив суфікс "D" для видалення файлів. Наскільки я знаю, вам доведеться додати рядок до кожного суфіксу.
Кріс

Або зробіть це першим параметром команди X. Нічого з цього не вимагає zsh або псевдонімів, за винятком, мабуть, особливої ​​ідеї поставити трубу в псевдонім.
tripleee

1
Я не розумію, чому вам, здається, такий cutваріант подобається . Це просто не працює на моїй машині, використовуючи вихід svn st. Спробуйте svn st | cut -d' ' -f2просто подивитися, що трапиться.
Лінч

@ Sv1 ви можете написати цикл для визначення псевдонімів, оскільки псевдонім - це лише команда.
driftcatcher

8

Оскільки вам здається, що ви не знайомі зі сценаріями, ось приклад.

#!/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

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

$ cat file | sh script.sh 2
2
5

Або наведіть це як аргумент до сценарію:

$ sh script.sh 2 file
2
5

Тут, sh script.shякщо припустити, що сценарій зберігається як script.shу поточному каталозі; якщо ви збережете його з більш корисним іменем десь у своєму PATHі позначаєте його виконуваним, як у наведених вище інструкціях, явно використовуйте корисне ім'я замість (і ні sh).


Хороша ідея, але не дуже працює для мене, як на sh або bash. Це працює: #! / Bin / bash col = $ 1 зміна awk "{print \ $$ col}"
mgk

Дякую за цей пізній коментар. Оновлено ваше виправлення.
трійчатка


@fedorqui Дякую за відгуки, тут і в інших місцях! Оновлено відповідь. Зараз це трохи довше, тому якщо ви хочете, щоб у вас був найкоротший сценарій, перегляньте історію редагування оригінальної версії.
трійка

1
@fedorqui Дякую купу! Невеликий застереження до catприкладу з істеричних причин (-:
tripleee

5

Схоже, у вас вже є рішення. Щоб полегшити ситуацію, чому б просто не поставити свою команду в скрипт bash (з короткою назвою) і просто запустити це, а не вводити цю команду "long" кожен раз?


На мою думку, це просто не так круто. Чому? Ну, я не хочу забивати свій .bashrc різними комбінаціями клавіш, які роблять це та інше, по суті, записуючи мета-оболонку. Його досить пристрасно, як є. Сказавши це, ваша пропозиція не є поганою.
Sv1

2
.bashrc? Чому б вам це захарастити речі, що не стосуються башу. Що я роблю, це писати окремі сценарії для кожного "набору" команд і поміщати їх у ~/scriptsкаталог. Потім додайте ціле ~/scriptsдо мого, PATHщоб я міг просто називати їх по імені, коли мені це потрібно.
Тарек Фадель

4
Тоді не вкладайте його у свій .bashrc. Створіть сценарій у ~ / bin та переконайтесь, що він знаходиться у вашій PATH.
трійка

2

Якщо ви все в порядку з ручним вибором стовпця, ви можете бути дуже швидкими, використовуючи pick :

svn st | pick | xargs rm

Просто перейдіть до будь-якої комірки 2-го стовпчика, натисніть cі потім натиснітьenter


Я спробував інструмент "вибрати", на який ви посилаєтесь, і мені це дуже подобається. Це дуже добре для багатьох ситуацій, коли я хочу надрукувати вибрані стовпці, але не хочу набирати "awk" {print $ 3} '"просто для отримання потрібного стовпця. На жаль, назва суперечить іншому інструменту "pick", який видається більш популярним - його можна встановити за допомогою "apt install pick". Тому я перейменував ваш інструмент, щоб "забрати" у своїй системі, і маю намір продовжувати його використовувати. Дякуємо за публікацію довідки.
William Dye

1

Зауважте, що шлях до файлу не повинен знаходитися у другому стовпці виводу 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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.