Yang Xu
Yang Xu

Reputation: 65

Write specific columns of files into another files, Who can give me a more concise solution?

I have a troublesome problem about writing specific columns of the file into another file, more details are I have the file1 like below, I need to write the first columns exclude the first row to file2 with one line and separated with '|' sign. And now I have a solution by sed and awk, this missing last step inserts into the top of file2, even though I still believe there should be some more concise solution on account of powerful of awk、sed, etc. So, Who can offer me another more concise script?

sed '1d;s/ .//' ./file1 | awk '{printf "%s|", $1; }' | awk '{if (NR != 0) {print substr($1, 1, length($1) - 1)}}'

file1:

col_name    data_type   comment
aaa         string     null
bbb         int     null
ccc         int     null

file2:

xxx   ccc(whatever is this)

The result of file2 should be this :

aaa|bbb|ccc
xxx   ccc(whatever is this)

Upvotes: 0

Views: 893

Answers (4)

tripleee
tripleee

Reputation: 189457

Here is a simple Awk script to merge the files as per your spec.

awk '# From the first file, merge all lines except the first
NR == FNR { if (FNR > 1) { printf "%s%s", sep, $1; sep = "|"; } next }
# We are in the second file; add a newline after data from first file
FNR == 1 { printf "\n" }
# Simply print all lines from file2
1' file1 file2

The NR==FNR condition is true when we are reading the first input file: The overall line number NR is equal to the line number within the current file FNR. The final 1 is a common idiom for printing all input lines which make it this far into the script (the next in the first block prevent lines from the first file to reaching this far).

For conciseness, you can remove the comments.

awk 'NR == FNR { if (FNR > 1) { printf "%s%s", sep, $1; sep = "|"; } next }
FNR == 1 { printf "\n" } 1' file1 file2

Generally speaking, Awk can do everything sed can do, so piping sed into Awk (or vice versa) is nearly always a useless use of sed.

Upvotes: 0

madprops
madprops

Reputation: 4023

I'm learning awk at the moment.

awk 'BEGIN{a=""} {if(NR>1) a = a $1 "|"} END{a=substr(a, 1, length(a)-1); print a}' file1

Edit: Here's another version that uses an array:

awk 'NR > 1 {a[++n]=$1} END{for(i=1; i<=n; ++i){if(i>1) printf("|"); printf("%s", a[i])} printf("\n")}' file1

Upvotes: 0

potong
potong

Reputation: 58430

This might work for you (GNU sed):

sed -z 's/[^\n]*\n//;s/\(\S*\).*/\1/mg;y/\n/|/;s/|$/\n/;r file2' file1

Process file1 "wholemeal" by using the -z command line option.

Remove the first line.

Remove all columns other than the first.

Replace newlines by |'s

Replace the last | by a newline.

Append file2.


Alternative using just command line utils:

tail +2 file1 | cut -d' ' -f1 | paste -s -d'|' | cat - file2

Tail file1 from line 2 onwards.

Using the results from the tail command, isolate the first column using a space as the column delimiter.

Using the results from the cut command, serialize each line into one, delimited by |',s.

Using the results from the paste, append file2 using the cat command.

Upvotes: 0

glenn jackman
glenn jackman

Reputation: 246847

Assuming there's no whitespace in the column 1 data, in increasing length:

sed -i "1i$(awk 'NR > 1 {print $1}' file1 | paste -sd '|')" file2

or

ed file2 <<END
1i
$(awk 'NR > 1 {print $1}' file1 | paste -sd '|')
.
wq
END

or

{ awk 'NR > 1 {print $1}' file1 | paste -sd '|'; cat file2; } | sponge file2

or

mapfile -t lines < <(tail -n +2 file1)
col1=( "${lines[@]%%[[:blank:]]*}" )
new=$(IFS='|'; echo "${col1[*]}"; cat file2)
echo "$new" > file2

Upvotes: 1

Related Questions