13

Let us suppose that there is a command such as:

cat /boot/config-3.19.0-32-generic | grep CONFIG_ARCH_DEFCONFIG

The output is as such:

CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig"

Now, my question is: Are there any commands which will only print what is inside the inverted commas, i.e., " "?

And could you please explain the command a little? Thank you! in advance.

7
  • 5
    Note that using cat in a pipe is almost always a waste of resources (AKA UUOC); grep can read its input from a file already (i.e. grep CONFIG_ARCH_DEFCONFIG /boot/config-3.19.0-32-generic does exactly the same thing, but 1. It's shorter 2. It's easier to understand 3. It doesn't fork an additional shell and an additional process). In 99% of the cases, using cat at the start of the pipe without concatenating multiple files it's just harmful. :)
    – kos
    Dec 25, 2015 at 9:28
  • @kos - Thanx! Didn't know that as I have just started using linux. Will keep it in mind.
    – Raphael
    Dec 25, 2015 at 9:30
  • Np! I'm leaving my comment above for other people stumbling across this question.
    – kos
    Dec 25, 2015 at 9:33
  • The initial cat, though useless in this case, would make editing the entire line of commands easier in the future in case you want to change / add / remove something later, maybe a tr or cut, etc, don't have to find & move the filename, make sure the other command supports it, find where to put it, etc. And for a small test file it only adds 0.002s. (I've probably spent more time typing this than I'll ever save in a lifetime of avoiding superfluous cat's)
    – Xen2050
    Dec 25, 2015 at 11:02
  • 1
    @Xen2050 why does the cat help here? You can do grep foo file | tr or ... | cut just as easily as cat file | tr | grep .... The cat just adds an extra five characters, an extra pipe and an extra program call and doesn't simplify anything.
    – terdon
    Dec 25, 2015 at 14:11

6 Answers 6

17

Yes, you can do that. Your command would be:

cat /boot/config-3.19.0-32-generic | grep CONFIG_ARCH_DEFCONFIG | awk -F'"' '{print $2}'

which would return only:

arch/x86/configs/x86_64_defconfig

The awk command uses field separators with the -F command, and to set it to use double-quotes, you type it in with single-quotes around it like -F'"'. Then the '{print $2}' tells awk to print the second set after the field separator.

Hope this helps!

3
  • 14
    @Terrance, In this case this is a useless use of cat and grep. You could replace cat and grep part with awk -F'"' '/CONFIG_ARCH_DEFCONFIG/{print $2}' /boot/config-3.19.0-32-generic . Less plumbing , letting AWK do all the work, which it is more than capable of doing Dec 25, 2015 at 6:36
  • Agree with @Serg
    – Tung Tran
    Dec 25, 2015 at 8:47
  • @Serg No problems. I understand what you're saying. I was only adding on to his original command by adding on the awk command. =)
    – Terrance
    Dec 25, 2015 at 15:24
11

You can do that with a single grep command:

grep -Po '^CONFIG_ARCH_DEFCONFIG="\K[^"]*' /boot/config-3.19.0-32-generic

Or (a bit longer and more convulted):

grep -Po '^CONFIG_ARCH_DEFCONFIG="\K.*?(?=")' /boot/config-3.19.0-32-generic
  • -P: tells grep to interpret the pattern as a PCRE (Perl Compatible Regular Expression);
  • -o: tells grep to print only the match;
  • ^CONFIG_ARCH_DEFCONFIG=": matches a CONFIG_ARCH_DEFCONFIG=" string at the start of the line;
  • \K: discards the previously matched substring;

#1:

  • [^"]*: matches any number of any character not " (greedily).

#2:

  • .*?: matches any number of any character (lazily);
  • (?="): lookahead (zero-lenght assertion, it doesn't match any character); matches if the following character is a ".
% grep -Po '^CONFIG_ARCH_DEFCONFIG="\K[^"]*' /boot/config-4.2.0-16-generic
arch/x86/configs/x86_64_defconfig
% grep -Po '^CONFIG_ARCH_DEFCONFIG="\K.*?(?=")' /boot/config-4.2.0-16-generic
arch/x86/configs/x86_64_defconfig
1
  • I love learning more than one way to achieve the same results. Great answer! =)
    – Terrance
    Dec 27, 2015 at 2:07
10

There are many ways to skin this cat, here is a sed way:

sed -nr 's/^CONFIG_ARCH_DEFCONFIG="([^"]+)"$/\1/p' /boot/config-3.19.0-32-generic

Here we are matching the line and capturing the desired portion i.e. the portion within double quotes (([^"]+)) and then replacing the whole line with the captured group (\1) only.

Example:

% sed -nr 's/^CONFIG_ARCH_DEFCONFIG="([^"]+)"$/\1/p' /boot/config-3.13.0-32-generic
arch/x86/configs/x86_64_defconfig
10

What, no perl?

grep CONFIG_ARCH_DEFCONFIG /boot/config-3.19.0-32-generic | 
    perl -pe 's/.*?"([^"]*).*/$1/'

The perl will -print every line after applying the script given by -e. The s/foo/bar/ will substitute foo with bar. Patterns in parentheses are "captured" and can be referred to as $1, $2 ... $N where $1 is the 1st pattern captured, $2 the second etc. The regular expression will look for everything until the first quote (.*?"), then capture 0 or more non-" characters ([^"]*) and then everything else. The whole thing is replaced with the captured pattern.

You can also leave the pattern matching to perl:

perl -ne 's/.*CONFIG_ARCH_DEFCONFIG="([^"]*).*/$1/ && print' /boot/config-3.19.0-32-generic
4
  • 2
    I knew you would join at some point :P +1
    – heemayl
    Dec 25, 2015 at 14:25
  • then I would produce a python code.. Dec 26, 2015 at 5:57
  • with open('/boot/config-3.19.0-32-generic') as f: for line in f: if line.startswith('CONFIG_ARCH_DEFCONFIG'): print line.split('"')[1] Dec 26, 2015 at 5:59
  • @AvinashRaj good stuff, care to post this please ? I've posted one with regex as well. Jan 22, 2016 at 2:29
9

Here is a combination of grep and cut, that does the same job.

$ grep "CONFIG_ARCH_DEFCONFIG" /boot/config-3.19.0-32-generic | cut -d"\"" -f2                                                
arch/x86/configs/x86_64_defconfig

Explanation:

  • grep "CONFIG_ARCH_DEFCONFIG" /boot/config-3.19.0-32-generic is the part that finds the line, in the standard grep syntax:grep [OPTIONS] PATTERN [FILE...]. The output goes through pipe to the next stage
  • cut -d"\"" -f2. This part uses cut to crop-off text separated by specific delimiter (which is specified with -d flag). We have to escape the double quote with backslash so that shell allows taking double quote as one of the options to the cut command, rather than input to the shell itself. Now cut will treat output from grep as separated by " and split into three columns, CONFIG_ARCH_DEFCONFIG, arch/x86/configs/x86_64_defconfig, and empty space. The line we need is the second column, that means we need to use -f2 flag.
3

Since I am currently learning python here is a version using exactly that.

#!/usr/bin/env python
import re

reg = re.compile('CONFIG_ARCH_DEFCONFIG')

with open("/boot/config-3.19.0-32-generic") as file :
   for line in file:
       if reg.match(line):
           print line.split('"')[1]

Sample run:

DIR:/TECH-BOOKS
skolodya@ubuntu:$ ./extractString.py                                           
arch/x86/configs/x86_64_defconfig

DIR:/TECH-BOOKS
skolodya@ubuntu:$ cat ./extractString.py                                       
#!/usr/bin/env python
import re

reg = re.compile('CONFIG_ARCH_DEFCONFIG')

with open("/boot/config-3.19.0-32-generic") as file :
   for line in file:
       if reg.match(line):
           print line.split('"')[1]
2
  • indentation is very7 very important in python.. Jan 22, 2016 at 2:36
  • 1
    You don't need to go for regexd, just use mine ie, line.startswith because re.match is much slower than startswith Jan 22, 2016 at 2:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .