How do you extract a particular column or row from the output of a command?

6,318

Solution 1

That's exactly what awk was made for. Using the output of xinput on my system:

$ xinput --list --short
⎡ Virtual core pointer                      id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
⎜   ↳ SIGMACHIP USB Keyboard                    id=12   [slave  pointer  (2)]
⎜   ↳ Logitech M325                             id=14   [slave  pointer  (2)]
⎜   ↳ AlpsPS/2 ALPS DualPoint Stick             id=17   [slave  pointer  (2)]
⎜   ↳ AlpsPS/2 ALPS DualPoint TouchPad          id=16   [slave  pointer  (2)]
⎣ Virtual core keyboard                     id=3    [master keyboard (2)]
    ↳ Virtual core XTEST keyboard               id=5    [slave  keyboard (3)]
    ↳ Power Button                              id=6    [slave  keyboard (3)]
    ↳ Video Bus                                 id=7    [slave  keyboard (3)]
    ↳ Power Button                              id=8    [slave  keyboard (3)]
    ↳ SIGMACHIP USB Keyboard                    id=11   [slave  keyboard (3)]
    ↳ Dell WMI hotkeys                          id=18   [slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard              id=13   [slave  keyboard (3)]
    ↳ Sleep Button                              id=9    [slave  keyboard (3)]
    ↳ UVC Camera (046d:0819)                    id=10   [slave  keyboard (3)]

$ xinput --list --short | awk -F"\t" '{print $2}'
id=2
id=4
id=12
id=14
id=17
id=16
id=3
id=5
id=6
id=7
id=8
id=11
id=18
id=13
id=9
id=10

awk will automatically split each input line into fields on the value given by -F. By default, it splits on whitespace, but here we need a tab. The 1st field is $1, the second $2 etc.

Alternatively, you can use cut:

$ xinput --list --short | cut -f2
id=2
id=4
id=12
id=14
id=17
id=16
id=3
id=5
id=6
id=7
id=8
id=11
id=18
id=13
id=9
id=10

You can save the output in a shell variable just like you would for any other command:

$ ids=$(xinput --list --short | awk -F"\t" '{print $2}')
$ echo $ids
id=2 id=4 id=12 id=14 id=17 id=16 id=3 id=5 id=6 id=7 id=8 id=11 id=18 id=13 id=9 id=10
$ echo "$ids"
id=2
id=4
id=12
id=14
id=17
id=16
id=3
id=5
id=6
id=7
id=8
id=11
id=18
id=13
id=9
id=10

You could also save it as an array:

$ ids=( $(xinput --list --short | awk -F"\t" '{print $2}') )
$ echo ${ids[@]}
id=2 id=4 id=12 id=14 id=17 id=16 id=3 id=5 id=6 id=7 id=8 id=11 id=18 id=13 id=9 id=10
$ echo ${ids[2]}
id=12

Solution 2

Knowing that the items are tab separated, we can use shell-only way with $IFS variable and while read ; do . . .done structure.

$ xinput | while IFS=$'\t' read ONE TWO THRE ; do                                        
> echo $TWO
> done
id=2
id=4
id=11
id=3
id=5
id=6
id=7
id=8
id=9
id=10
id=12

To store items in a variable, we can use arrays, and

$ xinput | { while IFS=$'\t' read ONE TWO THRE ; do                                     
> array+=( "$TWO" )
> done ;
> echo ${array[@]} 
> }
id=2 id=4 id=11 id=3 id=5 id=6 id=7 id=8 id=9 id=10 id=12

Notice me using command | { command1 ; command2 ; command3 } structure. You will quickly learn that pipes start subshells and variables in subshells don't affect the main shell , thus you have to come up with some way of preserving those variables.

As for extracting a row , well that's fairly easy with grep:

    $ xinput | grep 'Virtual core keyboard'
    ⎣ Virtual core keyboard                     id=3    [master keyboard (2)] # extract line with specific string

    ↳ Toshiba input device                      id=12   [slave  keyboard (3)]
$ xinput | sed -n '3p' # extract 3rd line                                                          
⎜   ↳ SynPS/2 Synaptics TouchPad                id=11   [slave  pointer  (2)]

Solution 3

to extract the column you could try awk

% xinput --list --short | awk '{print $3}'
core
Virtual
SynPS/2
core
core
Button
Bus
...

to assign that output to a variable a. note the value of this variable will be a string containing newlines after each word - not the easiest to work with. Probably better to assign to an array.

% a=$(xinput --list --short | awk '{print $3}')
vel@ubuntu:/media/michael/3ae9487f-1652-400e-8136-fe63519941ed% echo $a
core
Virtual
SynPS/2
core
core
Button
Bus
Button
USB2.0
WMI
Translated
Share:
6,318

Related videos on Youtube

TellMeWhy
Author by

TellMeWhy

I Wonder

Updated on September 18, 2022

Comments

  • TellMeWhy
    TellMeWhy over 1 year

    Example:

    abcd@abcd-abcde:~$ xinput --list --short
    
    Virtual core pointer
    
    ↳ SynPS/2 Synaptics TouchPad                id=11   [slave  pointer  (2)]
    
    ↳ Logitech USB RECEIVER                     id=12   [slave  pointer  (2)]
    

    How would I extract a column from the output, say the second one? And, for example, store it in a variable?

    Is it possible to do this?

  • terdon
    terdon almost 8 years
    I think the OP means the second output column, the ID field. You can get that with awk -F"\t" {print $2}.
  • the_velour_fog
    the_velour_fog almost 8 years
    @terdon cool, yes that was only my first iteration, but yeah you put the output into an array which is better for OP too
  • TellMeWhy
    TellMeWhy almost 8 years
    What if I want to get the first column? Will the arrows be included? Since I'm not using Linux atm I can't test right now..
  • terdon
    terdon almost 8 years
    @DevRobot fields are defined by the field separator. Here, I'm using \t, tab. Anything up to the 1st tab will be considered the first field, so yes, the arrows will be included.