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.