here is my sample file:
Host dns2
HostName 172.20.4.80
User root
Port 22
Host dns1
HostName 172.20.4.75
User root
Port 22
Host dns3
HostName 172.20.4.76
User root
Port 22
Host dns4
HostName 172.20.4.77
User root
Port 22
Host dns5
HostName 172.20.4.78
User root
Port 22
Host dns6
HostName 172.20.4.79
User root
Port 22
i want to print only one block means for example
Host dns1
HostName 172.20.4.75
User root
Port 22
output :
Host: dns2 HostName: 172.20.4.80 User: root Port: 22
but in this example all blocks have 4 lines maybe they reach to 5 or more lines later so i want to print from Host to first blank line or remove from Host to first blank line
im really bad at regex and need this to complete my script
thank you
I think that you basically want this:
awk -v RS='' '/dns1/' file
Unset the record separator so that each block is treated as a record, then print whichever record matches the pattern.
Or to use a shell variable:
host=dns1
awk -v host="$host" -v RS='' '$0 ~ host' file
In both of these examples, I'm using the fact that the default action is { print }
. As you will likely be changing the output by using { printf ... }
you may want to consider adding an exit
statement to avoid processing the rest of the file unnecessarily.
a similar awk
$ awk -v RS= -v OFS=' ' '{for(i=1;i<NF;i+=2) $i=$i":"}1' hosts
Host: dns2 HostName: 172.20.4.80 User: root Port: 22
Host: dns1 HostName: 172.20.4.75 User: root Port: 22
Host: dns3 HostName: 172.20.4.76 User: root Port: 22
Host: dns4 HostName: 172.20.4.77 User: root Port: 22
Host: dns5 HostName: 172.20.4.78 User: root Port: 22
Host: dns6 HostName: 172.20.4.79 User: root Port: 22
will give you all records in the desired output format. You can filter either this output further or add a pattern such as
$ awk -v RS= -v OFS=' ' '{for(i=1;i<NF;i+=2) $i=$i":"} /dns2/' hosts
Host: dns2 HostName: 172.20.4.80 User: root Port: 22
if want to exit after processing the selected record, you need to slightly change the script
$ awk -v RS= -v OFS=' ' '/dns2/{for(i=1;i<NF;i+=2) $i=$i":"; print; exit}' hosts
Host: dns2 HostName: 172.20.4.80 User: root Port: 22
If you want to select everything except one record you can negate the pattern (and remove exit)
$ awk -v RS= -v OFS=' ' '!/dns2/{for(i=1;i<NF;i+=2) $i=$i":"; print}' hosts
Host: dns1 HostName: 172.20.4.75 User: root Port: 22
Host: dns3 HostName: 172.20.4.76 User: root Port: 22
Host: dns4 HostName: 172.20.4.77 User: root Port: 22
Host: dns5 HostName: 172.20.4.78 User: root Port: 22
Host: dns6 HostName: 172.20.4.79 User: root Port: 22
Note that sed inplace replacement needs an intermediary file. If you want to replace the original file with the formatted one sans one record, you can use this command pattern on the last awk statement
$ awk ... > temp && mv temp original
UPDATE: setting OFS
will change all the separators between fields. You want to logically group them by name: value
, so change the script as such
$ awk -v RS= '{for(i=1;i<NF;i++) $i=$i (i%2?":":"\t")}1' hosts
Host: dns2 HostName: 172.20.4.80 User: root Port: 22
Host: dns1 HostName: 172.20.4.75 User: root Port: 22
Host: dns3 HostName: 172.20.4.76 User: root Port: 22
Host: dns4 HostName: 172.20.4.77 User: root Port: 22
Host: dns5 HostName: 172.20.4.78 User: root Port: 22
Host: dns6 HostName: 172.20.4.79 User: root Port: 22
which sets a tab delimiter after even positioned fields.
Not different than Tom Fenech approach, since it uses the record separator, but it plays with the field separator too to obtain the desired output:
awk -v RS='' -F'\n[\t ]*' -v OFS=' ' '/dns1/{$1=$1;print}' file
When you change the output field separator, you need to use $1=$1
(or $0=$0
or with any other field) to force awk to re-evaluate the record and to take in account the new field separator.
Notes: you can exit awk when a matching block is found with the exit
command. This avoids to process all the end of the file. You can also only test the pattern /dns1/
with the first field.
awk -v RS='' -F'\n[\t ]*' -v OFS=' ' '$1~/dns1/{$1=$1;print;exit}' file
If you add semi-colons to the result, since you modify the fields, the $1=$1
trick becomes useless. You can write:
awk -v RS='' -F'\n[\t ]*' -v OFS=' ' '$1~/dns1/{for(i=1;i<=NF;i++){sub(" ", ": ", $i)};print;exit}' file
To print the 3rd record:
$ awk -v RS= -F'\n[[:blank:]]+' -v OFS='\t' 'NR==3{$1=$1; gsub(/ +/,": "); print}' file
Host: dns3 HostName: 172.20.4.76 User: root Port: 22
To print the records that contains dns4
:
$ awk -v RS= -F'\n[[:blank:]]+' -v OFS='\t' '/dns4/{$1=$1; gsub(/ +/,": "); print}' file
Host: dns4 HostName: 172.20.4.77 User: root Port: 22
To print all records except those that contain dns3
, dns4
, or dns5
:
$ awk -v RS= -F'\n[[:blank:]]+' -v OFS='\t' '!/dns[345]/{$1=$1; gsub(/ +/,": "); print}' file
Host: dns2 HostName: 172.20.4.80 User: root Port: 22
Host: dns1 HostName: 172.20.4.75 User: root Port: 22
Host: dns6 HostName: 172.20.4.79 User: root Port: 22
This might work for you (GNU sed):
sed -n '/Host dns1/{:a;N;/^\s*$/M!ba;s/\n\s*/ /g;s/\s*$//p}' file
This focuses in on the required string, then appends following lines until a blank one and finally manipulates the new string that is gathered into the required output.
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.