Bash: the shortest way to get the nth output column

Let's say that during the working day you repeatedly come across the following form of column output from some command in bash (in my case, from executing svn st in the Rails working directory):

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

in order to work with the output of your command โ€” in this case, the file names โ€” some sort of parsing is needed so that the second column can be used as input for the next command.

What I did was use awk to get the second column, for example. when I want to delete all files (not that typical usecase :), I would do:

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

As I print this a lot, the natural question is: is there a shorter (thus colder) way to do this in bash?

Note: I ask, in fact, a shell issue, although my specific example is in my svn workflow. If you think the workflow is stupid and offers an alternative approach, I probably wonโ€™t vote for you, but others can, since the question here is how to get the output of the nth column command in bash, in the shortest possible way . Thank:)

+112
bash awk
Sep 06 '11 at 6:13
source share
8 answers

You can use cut to access the second field:

 cut -f2 

Edit: Sorry, did not understand that SVN does not use tabs in its output, so it is a little useless. You can configure cut to output, but it's a little fragile - something like cut -c 10- will work, but the exact value will depend on your setting.

Another option: sed 's/.\s\+//'

+82
06 Sep '11 at 6:19 06:19
source share

To accomplish the same thing as:

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

using only bash, you can use:

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

Of course, it is not shorter, but it is a bit more efficient, and it handles spaces in your files correctly.

+69
Sep 06 '11 at 6:27
source share

I ended up in the same situation and ended up adding these aliases to my .profile file:

 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}'" 

Which allows me to write things like this:

 svn st | c2 | xargs rm 
+21
Apr 07 '17 at 17:43 on
source share

Try Zsh. It supports the suffix alias so that you can define X in your .zshrc as

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

then you can do:

 cat file X 

You can take it one step further and define it for the nth column:

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

which will output the nth column of the file "file". You can do this for grep output or for smaller output. This is a very handy and killer feature of Zsh.

You can take another step and define D as follows:

 alias -g D="|xargs rm" 

Now you can enter:

 cat file X1 D 

delete all files specified in the first column of the file "file".

If you know bash, zsh is not big, except for some new features.

Hth Chris

+13
Sep 06 '11 at 6:21
source share

Since you don't seem to be familiar with the scripts, here is an example.

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

If you save this to ~/bin/x and make sure that ~/bin is in your PATH (now this is what you can and should put in your .bashrc ), you have the shortest possible command to extract column n; x n.

The script must perform the correct error checking and pledge when called with a non-numeric argument or the wrong number of arguments, etc .; but an extension of this major version will be available in block 102.

You might want to extend the script to allow a different column delimiter. Awk by default parses input into fields in a space; to use another delimiter, use -F ':' , where : is the new delimiter. Implementing this as an option for a script makes it a little longer, so I leave this as an exercise for the reader.




Using

For file file :

 1 2 3 4 5 6 

You can pass it through stdin (using the useless cat just as a placeholder for something more useful);

 $ cat file | sh script.sh 2 2 5 

Or specify it as a script argument:

 $ sh script.sh 2 file 2 5 

Here sh script.sh assumes that the script is saved as script.sh in the current directory; if you save it with a more useful name somewhere in your PATH and mark it executable as in the instructions above, use a useful name instead (and not sh ) instead.

+6
Sep 06 2018-11-11T00:
source share

It looks like you already have a solution. To simplify the task, why not just put your command in a bash script (with a short name) and just run it instead of typing this "long" command every time?

+4
Sep 06 '11 at 6:17
source share

If it will be convenient for you to manually select a column, you can be very fast using select :

 svn st | pick | xargs rm 

Just go to any cell in the second column, press c , and then press enter

+2
Jan 09 '16 at 4:33
source share

Note that the file path does not have to be in the second column of svn st output. For example, if you modify a file and change its property, this will be the third column.

See possible output examples in:

 svn help st 

Output Example:

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

I suggest cutting the first 8 characters:

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

If you want to be 100% sure and deal with fancy file names with a space at the end, for example, you need to parse the xml output:

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

Of course, you can use some real XML parser instead of grep / sed.

+1
Sep 06 2018-11-11T00:
source share



All Articles