简体   繁体   中英

How to print $1, $2 and then all remaining parameters together in AWK

I'm making a script that generates aliases/abbreviations from a base file. The base file structure is something like this:

sctl   sudo         systemctl
pac    sudo         pacman

This works fine with the following code that reads the base file, removes comments and awks the abbreviation line on the abbreviation file:

    sed "s/\s*#.*$//;/^\s*$/d" $command_file | 
    awk -v c=$cmd -v o="$comp" '{ print c" "$1""o"\""$2" "$3"\"" }' >> $file

And the end result would be something like this:

abbr sctl "sudo systemctl"
abbr pac "sudo pacman"

But this code doesn't work when the line has many parts after the 3rd parameter:

svu    playerctl    -p spotify volume +0.05

How can i go about printing in that format? $1 $2 ($3..$N)

You can erase the first two fields and trim the space from the remainder, eg.

{ 
  printf "%s %s ", $1, $2
  $1=$2=""; sub(/^\s*/, "", $0);
  printf "\"%s\"\n", $0
}

With output like,

svu playerctl "-p spotify volume +0.05"

Note: the \\s regex requires gnu awk as pointed out by Ed Morton.

You never need sed when you're using awk. Given this input file:

$ cat file
sctl   sudo         systemctl   # here is a comment
        # and here is another
pac    sudo         pacman

svu    playerctl    -p spotify volume +0.05

here's what your sed+awk outputs:

$ sed "s/\s*#.*$//;/^\s*$/d" file |  awk -v c="abbr" -v o=" " '{ print c" "$1""o"\""$2" "$3"\"" }'
abbr sctl "sudo systemctl"
abbr pac "sudo pacman"
abbr svu "playerctl -p"

which you can get just from awk alone:

$ awk -v c="abbr" -v o=" " '{sub(/\s*#.*/,"")} NF{print c" "$1""o"\""$2" "$3"\""}' file
abbr sctl "sudo systemctl"
abbr pac "sudo pacman"
abbr svu "playerctl -p"

and which you can then adjust to do what you want:

$ awk -v c="abbr" -v o=" " '{sub(/\s*#.*/,"")} NF{x=$1; sub(/^\S+\s+/,""); $1=$1; print c, x o "\"" $0 "\""}' file
abbr sctl "sudo systemctl"
abbr pac "sudo pacman"
abbr svu "playerctl -p spotify volume +0.05"

or (I can't tell from your question what you want inside/outside of the double quotes):

$ awk -v c="abbr" -v o=" " '{sub(/\s*#.*/,"")} NF{x=$1" "$2; sub(/^(\S+\s+){2}/,""); $1=$1; print c, x o "\"" $0 "\""}' file
abbr sctl sudo "systemctl"
abbr pac sudo "pacman"
abbr svu playerctl "-p spotify volume +0.05"

The above uses GNU awk for \\s and \\S - with other awks use [[:space:]] and [^[:space:]] instead.

Since we're using GNU awk, though, we can do the job more concisely and efficiently with the 3rd arg to match():

$ awk -v c="abbr" -v o=" " '{sub(/\s*#.*/,""); $1=$1} match($0,/(\S+) (.*)/,a){print c, a[1] o "\"" a[2] "\""}' file
abbr sctl "sudo systemctl"
abbr pac "sudo pacman"
abbr svu "playerctl -p spotify volume +0.05"

$ awk -v c="abbr" -v o=" " '{sub(/\s*#.*/,""); $1=$1} match($0,/(\S+ \S+) (.*)/,a){print c, a[1] o "\"" a[2] "\""}' file
abbr sctl sudo "systemctl"
abbr pac sudo "pacman"
abbr svu playerctl "-p spotify volume +0.05"

Substitute the two extra fields out of existence.

$ echo "svu playerctl -p spotify volume +0.05" | gawk '
  { print $1; $1 = ""
    print $2; $2 = ""
    print substr($0,3) } '
svu
playerctl
-p spotify volume +0.05

The substr removes the output field separators from the remnants of the first two fields.

Here is an awk (standard Linux - specific to gawk) script that does all the work in one sweep:

awk -v c="abbr" -v o=" " '/(^\s*$)|(^\s*#.*$)/ {next}  # discard empty lines and comments
{
    arg3=$0;                          # save current line to arg3 variable
    sub($1" "$2,"",arg3);             # remove $1  and $2 from arg3
    print(c" "$1""o"\""$2" "arg3"\"") # print formated output
}' input.txt

input.txt

ctl   sudo         systemctl
# comment line
pac    sudo         pacman
   # comment line
demo1  sudo         arg1 arg2 arg3

demo2  sudo         arg4 -arg5 -arg6 456
                         # comment line

Output:

abbr ctl "sudo          systemctl"
abbr pac "sudo          pacman"
abbr demo1 "sudo          arg1 arg2 arg3"
abbr demo2 "sudo          arg4 -arg5 -arg6 456"

Here is GNU sed version:

sed -r 's/(^[^ ]+)\s+([^ ]+)\s+(.*)/abbr \1 "\2 \3"/g' base_file
abbr sctl "sudo systemctl"
abbr pac "sudo pacman"
abbr svu "playerctl -p spotify volume +0.05"

Explanation: Here back-referencing is used, each column is captured into respective groups and later used as \\1 , \\2 , \\3 . Note that -r flag is used in above sed command to enable extended regex. If this flag is not available in the target machine, then following command can be used:

sed  's/\(^[^ ]\+\)\s\+\([^ ]\+\)\s\+\(.*\)/abbr \1 "\2 \3"/g' base_file
abbr sctl "sudo systemctl"
abbr pac "sudo pacman"
abbr svu "playerctl -p spotify volume +0.05"

Only difference in the two commands in that ( , ) , + are escaped in the later.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM