cat specific columns in 3 files - awk

I have 3 files such as :
file1_file:
scaffold_159 625 YP_009345712 0.284 447 289 9 96675 95377 196 625 6.963E-38 158
scaffold_159 625 YP_009345714 0.284 447 289 9 96675 95377 196 625 6.963E-38 158
IDBA_scaffold_24562 625 YP_009345713 0.464 56 20 2 2549 2686 10 65 7.513E-03 37
file2_file:
scaffold_159 625 YP_009345717 0.284 447 289 9 96675 95377 196 625 6.963E-38 158
scaffold_159 625 YP_009345718 0.284 447 289 9 96675 95377 196 625 6.963E-38 158
IDBA_scaffold_24562 625 YP_009345719 0.464 56 20 2 2549 2686 10 65 7.513E-03 37
file3_file:
scaffold_159 625 YP_009345711 0.284 447 289 9 96675 95377 196 625 6.963E-38 158
scaffold_159 625 YP_009345723 0.284 447 289 9 96675 95377 196 625 6.963E-38 158
IDBA_scaffold_24562 625 YP_009345721 0.464 56 20 2 2549 2686 10 65 7.513E-03 37
and I would like to only get the 3th part of the 3 file in a single new_file.txt.
Here I should get :
YP_009345712
YP_009345714
YP_009345713
YP_009345717
YP_009345718
YP_009345711
YP_009345723
YP_009345721
From now I tried:
cat file_names.txt | while read line; do cat /path1/${line}/path2/${line}_file > new_file.txt; done
in file_names.txt I have :
file1
file2
file3
but I do not know how to extract only the 3th column...
Ps: the 3 files are not in the same directory :
/path1/file1/path2/file1_file
/path1/file2/path2/file2_file
/path1/file3/path2/file3_file

EDIT: After chatting with OP came to know that his/her files could be on different locations, so in that case could you please try following. Considering that you have an Input_file where all file names are there. I am yet to test it.
file_name=$(awk '{val=(val?val OFS:"")"/path1/" $0 "/path2/" $0} END{print val}' file_names.txt)
awk '{print $3}' "$file_name"
OR
awk '{print $3}' $(awk '{val=(val?val OFS:"")"/path1/" $0 "/path2/" $0} END{print val}' file_names.txt)
You could use awk here.
awk '{print $3}' /complete_path/file1 /complete_path/file2 /complete_path/file3

I think it can be simpler with
$ sed 's_.*_"path1/&/path2/&"_' filenames | xargs awk '{print $3}'
awk will be called only once.

So you have a file fnames.txt with hundreds of strings:
str1
str2
str3
str4
...
and each string represents a file located in
/path1/${str}/path2/${str}_file
where ${str} is a value from file fnames.txt.
Now you want to read the third column, from the third file only:
$ str="$(awk '(NR==3){print; exit}' fnames.txt)"
$ file="/path1/${str}/path2/${str}_file"
$ awk '{print $3}' "$file" > new_file.txt
Always remember the KISS principle

Related

print matched column from multiple inputs and concatenate the output

print matched column from multiple inputs and concatenate the output
A.lst
1091 1991 43.5 -30.1 -11.4
1091 1993 -11.2 -28.5 -2.7
1091 1997 35.8 -13.2 -4.5
1091 2003 -26.8 -23.9 0.6
1091 2007 23.8 64.8 3.5
1091 2008 -45.8 70.7 -6.0
1100 1967 24.5 -25.6 -12.7
1100 1971 -935.0 9.3 52.0
1100 1972 -388.8 59.1 20.4
1100 1974 17.7 48.9 3.0
B.lst
1091 1991 295 1
1091 1993 293 3
1091 1997 296 7
1091 2003 287 13
1091 2007 283 17
1091 2008 282 18
1100 1967 1419 3
1100 1971 56 7
1031 2023 283 17
1021 2238 282 18
1140 1327 1419 3
1150 3971 56 7
1100 1972 55 8
1100 1974 1445 10
By using this command (from previous, cant remember from where, i'll credit to them once i found it),
NR==FNR{
a[$1,$2]=$1; next
}
{
s=SUBSEP
k=$3 s $4
}k in a{ print $0 }
But I've no idea how to combine the output
it should print only matched (certain column $3 $4 from B.lst)
1091 1991 43.5 -30.1 -11.4 295 1
1091 1993 -11.2 -28.5 -2.7 293 3
1091 1997 35.8 -13.2 -4.5 296 7
1091 2003 -26.8 -23.9 0.6 287 13
1091 2007 23.8 64.8 3.5 283 17
1091 2008 -45.8 70.7 -6.0 282 18
1100 1967 24.5 -25.6 -12.7 1419 3
1100 1971 -935.0 9.3 52.0 56 7
1100 1972 -388.8 59.1 20.4 55 8
1100 1974 17.7 48.9 3.0 1445 10
Could you please try following.
awk 'FNR==NR{array[$1,$2]=$3 OFS $4;next} (($1,$2) in array){print $0,array[$1,$2]}' file_B file_A
Adding a non-one liner form of above solution now.
awk '
FNR==NR{
array[$1,$2]=$3 OFS $4
next
}
(($1,$2) in array){
print $0,array[$1,$2]
}
' file_B file_A
Explanation: Adding explanation for above code.
awk ' ##Starting awk program here.
FNR==NR{ ##Checking condition FNR==NR which will be TRUE when file_B is being read.
array[$1,$2]=$3 OFS $4 ##Creating an array named array whose index is $1,$2 and value is $3 OFS $4.
next ##Using next will skip all further statements from here.
} ##Closing FNR==NR condition BLOCK here.
(($1,$2) in array){ ##Checking condition if $1,$2 is present in array then do following.
print $0,array[$1,$2] ##Printing current line and then value of array with index of $1,$2
}
' file_B file_A ##Mentioning Input_file names here.

Problems making an awk between range of columns

I have a file called sds
$head sds
2557 386 fs://name/user/hive/ware/doc1/do_fact/date=20190313/fact=6
2593 393 fs://name/user/hive/ware/toc1/do_gas/idi_centr=6372/mes=20
2594 343 fs://name/user/hive/ware/dac2/do_gas2/idi_centr=6354/mes=21
349 307 fs://name/user/hive/ware/tec2/do_des/mes=25
340 332 fs://name/user/hive/ware/dc1/venta/year=2018/month=12
I want delete /user/hive/ware and replace $7 ~ /_1$ for 1and other $7 for 2 using awk.
The code that I used was:
awk -F"/" '{ if ($7 ~ /_1$/)
print $1"//"$3"/1/"$7-$NF
else
print $1"//"$3"/2/"$7-$NF}' sds
but the result is bad.
I would like and output like:
2557 386 fs://name/1/do_fact/date=20190313/fact=6
2593 393 fs://name/1/do_gas/idi_centr=6372/mes=20
2594 343 fs://name/2/do_gas2/idi_centr=6354/mes=21
349 307 fs://name/2/do_des/mes=25
340 332 fs://name/1/venta/year=2018/month=12
$ awk 'BEGIN{FS=OFS="/"} {sub("/user/hive/ware",""); $4=($4~/1$/ ? 1 : 2)} 1' file
2557 386 fs://name/1/do_fact/date=20190313/fact=6
2593 393 fs://name/1/do_gas/idi_centr=6372/mes=20
2594 343 fs://name/2/do_gas2/idi_centr=6354/mes=21
349 307 fs://name/2/do_des/mes=25
340 332 fs://name/1/venta/year=2018/month=12
or if you don't REALLY want to remove the string /user/hive/share and instead want to remove the 4th through 6th fields no matter their value:
$ awk 'BEGIN{FS=OFS="/"} {$4=$5=$6="\n"; sub(/(\/\n){3}/,""); $4=($4~/1$/ ? 1 : 2)} 1' file
2557 386 fs://name/1/do_fact/date=20190313/fact=6
2593 393 fs://name/1/do_gas/idi_centr=6372/mes=20
2594 343 fs://name/2/do_gas2/idi_centr=6354/mes=21
349 307 fs://name/2/do_des/mes=25
340 332 fs://name/1/venta/year=2018/month=12
with sed
$ sed -E 's_/user/hive/ware/[^/]+(.)/_/\1/_' file
2557 386 fs://name/1/do_fact/date=20190313/fact=6
2593 393 fs://name/1/do_gas/idi_centr=6372/mes=20
2594 343 fs://name/2/do_gas2/idi_centr=6354/mes=21
349 307 fs://name/2/do_des/mes=25
340 332 fs://name/1/venta/year=2018/month=12
it's not really a conditional replacement.
You can use awk and its gsub function to perform replacement on the selected columns.
awk 'BEGIN{FS=OFS="/"}{gsub("user/hive/ware/","");gsub(/^[^12]+/,"",$4)}1' inputfile
2557 386 fs://name/1/do_fact/date=20190313/fact=6
2593 393 fs://name/1/do_gas/idi_centr=6372/mes=20
2594 343 fs://name/2/do_gas2/idi_centr=6354/mes=21
349 307 fs://name/2/do_des/mes=25
340 332 fs://name/1/venta/year=2018/month=12

Compare two files according to first column and print whole line

I will ask my question with an example. I have 2 files:
File1-
TR100013|c0_g1
TR100013|c0_g2
TR10009|c0_g1
TR10009|c0_g2
File2-
TR100013|c0_g1 AT1G01360.1 78.79 165 35 0 301 795 19 183 2E-089 272
TR100013|c0_g2 AT1G01360.1 78.79 165 35 0 301 795 19 183 2E-089 272
TR10009|c0_g1 AT1G16240.3 77.42 62 14 0 261 76 113 174 4E-025 95.9
TR10009|c0_g2 AT1G16240.2 69.17 120 37 0 1007 648 113 232 2E-050 171
TR29295|c0_g1 AT1G22540.1 69.19 172 53 2 6 521 34 200 2E-053 180
TR49005|c5_g1 AT5G24530.1 69.21 302 90 1 909 13 39 340 5E-157 446
Expected Output :
TR100013|c0_g1 AT1G01360.1 78.79 165 35 0 301 795 19 183 2E-089 272
TR100013|c0_g2 AT1G01360.1 78.79 165 35 0 301 795 19 183 2E-089 272
TR10009|c0_g1 AT1G16240.3 77.42 62 14 0 261 76 113 174 4E-025 95.9
TR10009|c0_g2 AT1G16240.2 69.17 120 37 0 1007 648 113 232 2E-050 171
I want to compare two files. If the first column is same in both files, then print the whole line of second file which is common in both files.
Using awk:
awk 'NR==FNR{a[$1]++;next};a[$1]' file1 file2
grep can do the same:
grep -wf file1 file2
-w is to match whole word only.
-f specifies the file with the pattern.

Forming a variable for a graph using result of searching with awk

I´m using cacti to graph CPU usage of equipment with 7 modules, the command used shows 12 samples for each module. I need to use awk to find the pattern of each module name and after form a variable with this sintaxis [module]:[12th CPU sample], for example: MSCBC05:47
Below a extract of command output mentioned:
ACT AD-46 TIME 141216 1556 MSCBC05
PROCESSOR LOAD DATA
INT PLOAD CALIM OFFDO OFFDI FTCHDO FTCHDI OFFMPH OFFMPL FTCHMPH FTCHMPL
1 46 56250 656 30 656 30 1517 2 1517 2
2 47 56250 659 32 659 32 1448 1 1448 1
3 46 56250 652 22 652 22 1466 1 1466 1
4 47 56250 672 33 672 33 1401 0 1401 0
5 47 56250 674 38 674 38 1446 2 1446 2
6 45 56250 669 22 669 22 1365 1 1365 1
7 45 56250 674 26 674 26 1394 2 1394 2
8 46 56250 664 24 664 24 1396 0 1396 0
9 47 56250 686 24 686 24 1425 2 1425 2
10 47 56250 676 31 676 31 1386 0 1386 0
11 48 56250 702 25 702 25 1414 2 1414 2
12 47 56250 703 31 703 31 1439 2 1439 2
Complete output
https://dl.dropboxusercontent.com/u/33222611/raw_output.txt
I suggest
awk '$1 == "ACT" { sub(/\r/, ""); curmsc = $6 } curmsc != "" && $1 == "12" { print curmsc ":" $2; curmsc = "" }' raw_output.txt
Written more readably, that is
$1 == "ACT" { # In the first line of an ACT block
sub(/\r/, "") # remove the trailing carriage return. Could also use todos or so.
curmsc = $6 # remember MSC
}
curmsc != "" && $1 == "12" { # if we are in such a block and the first token is 12
print curmsc ":" $2 # print the stuff we want to know
curmsc = "" # then flag that we're outside a block
}

How to take the 10 last values from a file in awk

I have a file that contains this data:
345
234
232
454
343
676
887
324
342
355
657
786
343
879
088
342
121
345
534
657
767
I need to cut the last 10 values and put it in another file:
786
343
879
388
342
121
345
534
657
767
No need to use awk, just tail the data:
tail -n 10 input.txt > example.txt
If you really wanted to use awk, you have to keep track of the 10 last lines ($0) and print them in END. Though this would be overkill.
This is what the tail command is for:
$ tail -10 file
786
343
879
088
342
121
345
534
657
767
To store the output in a new file use to redirection operator:
$ tail -10 file > new_file
However if you really want to do it with awk then the brute force approach is to store each line in an array and print the last 10 elements at the end of file:
$ awk '{a[NR]=$0}END{for(i=(NR-9);i<=NR;i++)print a[i]}' file
786
343
879
088
342
121
345
534
657
767
Again, to store the output in a new file use the redirection operator:
$ awk '{a[NR]=$0}END{for(i=(NR-9);i<=NR;i++)print a[i]}' file > new_file
The previous method is a very inefficient method as we have to create an array the same size as the file we are reading. A much better approach is to use the modulus operator to just create an array of size 10 containing the last 10 lines read:
$ awk '{a[NR%10]=$0}END{for(i=NR%10+1;j++<10;i=++i%10) print a[i]}' file 
786
343
879
088
342
121
345
534
657
767
This can be generalized to the last n lines like so (i.e n=3):
$ awk '{a[NR%n]=$0}END{for(i=NR%n+1;j++<n;i=++i%n) print a[i]}' n=3 file
534
657
767
Code for GNU sed:
get the last 10 lines
sed ':a $q;N;11,$D;ba' file
get all but the last 10 lines
sed ':a $d;N;2,10ba;P;D' file