Print a specific part in an output

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.


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!


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

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

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

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.