bash:出力のn番目の列を取得する最短の方法


165

平日に、bashのコマンドから次の形式の列化された出力が繰り返し発生するとします(私の場合svn st、Railsの作業ディレクトリで実行した場合)。

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

コマンドの出力(この場合はファイル名)を処理するには、2番目の列を次のコマンドの入力として使用できるように、何らかの解析が必要です。

私がやっていることはawk、2番目の列を取得するために使用することです。たとえば、すべてのファイルを削除したい場合(これは典型的なユースケースではありません)、次のようにします。

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

私はこれを何度も入力するので、自然な質問は次のとおりです:これをbashで実行するためのより短い(したがってよりクールな)方法はありますか?

注:私の具体的な例はsvnワークフローですが、私が求めているのは基本的にシェルコマンドの質問です。ワークフローがばかげていると感じて別のアプローチを提案した場合、私はおそらくあなたを反対票を投じませんが、他の人はそうする可能性があります。 。ありがとう:)


1
コマンドを頻繁に使用する場合は、スクリプトを作成してパスに入れる方が適切です。必要に応じて、bashrcに関数を作成できます。列選択式を減らす意味がわかりません。
リンチ

1
あなたは正しい、そして私はそうするかもしれない。「ポイント」は、bashで
何か

1
また、どこかにsshを実行するときに.bashrcがないので、それがない場合の回避方法を知っておくと便利です。
Kos

回答:


125

を使用cutして2番目のフィールドにアクセスできます。

cut -f2

編集:申し訳ありませんが、SVNがその出力でタブを使用しないことを理解していなかったため、少し役に立たないのです。cut出力に合わせて調整できますが、それは少し壊れやすいです-のようなものcut -c 10- は機能しますが、正確な値は設定によって異なります。

別のオプションは次のようなものです: sed 's/.\s\+//'


1
出力で使用cut -f2してみてくださいsvn st。動作しないことがわかります。
リンチ、

私は本当の人svn stがその出力でタブを使用すると仮定しました。いくつかのテストの後、これはそうではないようです。くそー。
ポルジュ2011

21
-dこれを機能させるために適切な区切り文字を渡す。
Yogh

6
@Yoghの発言を拡張すると、区切り文字としてのスペースの場合はのようになりますcut -d" " -f2
adamyonk 2017

stdoutでawkを使用しない場合は、xargsを使用します。svnst | xargs | cut -d "" -f2
vr286

106

同じことを達成するには:

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

あなたが使用できるbashのみを使用して:

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

確かに短くはありませんが、少し効率的で、ファイル名の空白を正しく処理します。


何ですab、どのようにそれらを取得?
Timo

1
@Timo aは最初の列をb表し、残りの列を表します。2列目を印刷する場合は、の代わりにをread a b c;使用してください。これを使用して、grepパターンに従った一連のIDプロセスを取得したので、それらすべてに割り込むことができました。echorm
Matt Kleinsmith、2018年

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を試してください。これはサフィックスエイリアスをサポートしているため、.zshrcでXを次のように定義できます。

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"

これは、ファイル「file」のn番目の列を出力します。これは、grep出力またはそれ以下の出力でも実行できます。これは非常に便利で、zshのキラー機能です。

さらに一歩進んで、Dを次のように定義できます。

alias -g D="|xargs rm"

次のように入力できます。

cat file X1 D

ファイル「file」の最初の列に記載されているすべてのファイルを削除します。

bashを知っている場合、zshはいくつかの新機能を除いてほとんど変更されていません。

HTHクリス


ああ、上のコメントを入力しているときに回答が更新されたようです:)取得する列を動的に指定できますか、または.zshrcにn行が必要ですか(重要ではありませんが、興味があるだけです)
Sv1

投稿をさらに編集し、ファイルを削除するためのサフィックス「D」を定義しました。私が知る限り、各サフィックスごとに行を追加する必要があります。
Chris

または、Xコマンドの最初のパラメーターにします。これには、おそらくパイプをエイリアスに入れるという独特のアイデアを除いて、zshやエイリアスは必要ありません。
tripleee

1
どうしてあなたがこのcutオプションを気に入っているのか理解できません。私のマシンでは、の出力を使用しても機能しませんsvn stsvn st | cut -d' ' -f2何が起こるか見てみてください。
リンチ

@ Sv1では、エイリアスは単なるコマンドなので、エイリアスを定義するためのループを作成できます。
ドリフトキャッチャー2013年

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を抽出するための最短のコマンドがあります。x n。

スクリプトは、数値以外の引数または不正な数の引数などで呼び出された場合、適切なエラーチェックを行い、保釈する必要があります。しかし、この必要最低限​​のバージョンの拡張は、ユニット102になります。

おそらく、別の列区切り文字を使用できるようにスクリプトを拡張する必要があります。デフォルトでは、awkは空白のフィールドへの入力を解析します。別の区切り文字を使用する-F ':':は、where を新しい区切り文字として使用します。これをスクリプトのオプションとして実装すると少し長くなるので、読者のための演習として残しておきます。


使用法

ファイルを考えると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 shift awk "{print \ $$ col}"
mgk

この遅いコメントをありがとう。あなたの修正で更新されました。
tripleee、2015年

1
改善awk -v col=$col ...
fedorqui 'SO stop harming'

@fedorquiフィードバックをありがとうございます。回答を更新しました。少し長くなりましたので、できる限り短いスクリプトが必要な場合は、元のバージョンの変更履歴を参照してください。
Tripleee、2015

1
@fedorquiありがとうございます!catヒステリックな理由により、例に小さな警告を追加しました(-:
tripleee

5

すでに解決策があるようです。簡単にするために、コマンドをbashスクリプト(短い名前)に入れて、その「長い」コマンドを毎回入力する代わりに実行するだけではどうですか。


それは私の意見ではそれほどクールではありません。どうして?まあ、これを行うさまざまなショートカットで.bashrcをあふれさせたくないので、基本的にメタシェルを作成します。かなりエイリアス化されています。そうは言っても、あなたの提案は悪いものではありません。
Sv1

2
.bashrc?なぜあなたはそれを非bash関連のもので乱雑にしようとするでしょう。私が行うことは、コマンドの「セット」ごとに個別のスクリプトを記述し、それらをすべて~/scriptsディレクトリに配置することです。次に、全体~/scriptsを追加して、PATH必要なときに名前で呼び出すだけにします。
Tarek Fadel、2011

4
次に、それを.bashrcに入れないでください。〜/ binにスクリプトを作成し、PATHにあることを確認します。
トリプルリー2011

2

手動で列を選択することに問題がなければ、pickを使用すると非常に高速になる可能性があります。

svn st | pick | xargs rm

2列目の任意のセルに移動し、押してcからenter


あなたが参照した「ピック」ツールを試してみましたが、とても気に入っています。選択した列を印刷したいが、目的の列を取得するためだけに「awk '{print $ 3}'」と入力したくない多くの状況に非常に適しています。残念ながら、この名前は、より一般的なように思われる別の「ピック」ツールと競合しています。「apt install pick」でインストールできます。そこで、私のシステムでツールの名前を「pickk」に変更し、引き続き使用するつもりです。リファレンスを投稿していただきありがとうございます。
William Dye

1

ファイルパスはsvn st出力の2列目にある必要はありません。たとえば、ファイルを変更し、そのプロパティを変更すると、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/"$//'

もちろん、grep / sedの代わりに実際のXMLパーサーを使用することもできます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.