Tôi có một tập tin văn bản với định dạng sau. Dòng đầu tiên là "KEY" và dòng thứ hai là "GIÁ TRỊ".
KEY 4048:1736 string
3
KEY 0:1772 string
1
KEY 4192:1349 string
1
KEY 7329:2407 string
2
KEY 0:1774 string
1
Tôi cần giá trị trong cùng dòng với khóa. Vì vậy, đầu ra sẽ trông như thế này ...
KEY 4048:1736 string 3
KEY 0:1772 string 1
KEY 4192:1349 string 1
KEY 7329:2407 string 2
KEY 0:1774 string 1
Sẽ tốt hơn nếu tôi có thể sử dụng một số dấu phân cách như $
hoặc ,
:
KEY 4048:1736 string , 3
Làm cách nào để hợp nhất hai dòng thành một?
ôi
awk 'NR%2{printf "%s ",$0;next;}1' yourFile
lưu ý, có một dòng trống ở cuối đầu ra.
sed:
sed 'N;s/\n/ /' yourFile
paste
tốt cho công việc này:
paste -d " " - - < filename
Thay thế cho sed, awk, grep:
xargs -n2 -d'\n'
Điều này là tốt nhất khi bạn muốn tham gia N dòng và bạn chỉ cần đầu ra được phân tách không gian.
Câu trả lời ban đầu của tôi là xargs -n2
phân tách trên các từ thay vì các dòng. -d
có thể được sử dụng để phân chia đầu vào theo bất kỳ ký tự đơn nào.
Có nhiều cách để giết một con chó hơn là treo cổ. [1]
awk '{key=$0; getline; print key ", " $0;}'
Đặt bất cứ dấu phân cách nào bạn thích bên trong dấu ngoặc kép.
Tài liệu tham khảo:
Đây là một cách khác với awk
:
awk 'ORS=NR%2?FS:RS' file
$ cat file
KEY 4048:1736 string
3
KEY 0:1772 string
1
KEY 4192:1349 string
1
KEY 7329:2407 string
2
KEY 0:1774 string
1
$ awk 'ORS=NR%2?FS:RS' file
KEY 4048:1736 string 3
KEY 0:1772 string 1
KEY 4192:1349 string 1
KEY 7329:2407 string 2
KEY 0:1774 string 1
Như được chỉ ra bởi Ed Morton trong các bình luận, tốt hơn là thêm niềng răng cho an toàn và parens cho tính di động.
awk '{ ORS = (NR%2 ? FS : RS) } 1' file
ORS
là viết tắt của Dấu tách bản ghi đầu ra. Những gì chúng tôi đang làm ở đây là kiểm tra một điều kiện bằng cách sử dụng NR
lưu số dòng. Nếu modulo của NR
là một giá trị thực (> 0) thì chúng ta đặt Dấu tách trường đầu ra thành giá trị của FS
(Dấu tách trường) theo mặc định là khoảng trắng, nếu không, chúng ta sẽ gán giá trị của RS
(Dấu tách bản ghi) là dòng mới.
Nếu bạn muốn thêm ,
làm dấu phân cách thì hãy sử dụng như sau:
awk '{ ORS = (NR%2 ? "," : RS) } 1' file
Đây là giải pháp của tôi trong bash:
while read line1; do read line2; echo "$line1, $line2"; done < data.txt
Mặc dù có vẻ như các giải pháp trước đó sẽ hoạt động, nếu một sự bất thường duy nhất xảy ra trong tài liệu, đầu ra sẽ chuyển thành từng mảnh. Dưới đây là một chút an toàn hơn.
sed -n '/KEY/{
N
s/\n/ /p
}' somefile.txt
"ex" là một trình soạn thảo dòng có thể viết được trong cùng một gia đình như sed, awk, grep, v.v. Tôi nghĩ đó có thể là những gì bạn đang tìm kiếm. Nhiều bản sao/người kế vị hiện đại cũng có chế độ vi.
ex -c "%g/KEY/j" -c "wq" data.txt
Điều này nói cho mỗi dòng, nếu nó khớp với "KEY" thì thực hiện một j oin của dòng sau. Sau khi lệnh đó hoàn thành (đối với tất cả các dòng), đưa ra một w rite và q uit.
Bạn có thể sử dụng awk như thế này để kết hợp 2 cặp dòng:
awk '{ if (NR%2 != 0) line=$0; else {printf("%s %s\n", line, $0); line="";} } \
END {if (length(line)) print line;}' flle
Nếu Perl là một tùy chọn, bạn có thể thử:
Perl -0pe 's/(.*)\n(.*)\n/$1 $2\n/g' file.txt
Một biến thể nhỏ trên câu trả lời của glenn jackman bằng cách sử dụng paste
: nếu giá trị cho tùy chọn dấu phân cách -d
chứa nhiều hơn một ký tự, thì paste
sẽ chuyển qua từng ký tự một và kết hợp với các tùy chọn -s
xử lý cùng một tập tin đầu vào.
Điều này có nghĩa là chúng ta có thể sử dụng bất cứ thứ gì chúng ta muốn có như dấu phân cách cộng với chuỗi thoát \n
để hợp nhất hai dòng cùng một lúc.
Sử dụng dấu phẩy:
$ paste -s -d ',\n' infile
KEY 4048:1736 string,3
KEY 0:1772 string,1
KEY 4192:1349 string,1
KEY 7329:2407 string,2
KEY 0:1774 string,1
và ký hiệu đô la:
$ paste -s -d '$\n' infile
KEY 4048:1736 string$3
KEY 0:1772 string$1
KEY 4192:1349 string$1
KEY 7329:2407 string$2
KEY 0:1774 string$1
Điều này không thể làm là sử dụng dấu phân cách bao gồm nhiều ký tự.
Như một phần thưởng, nếu paste
tuân thủ POSIX, điều này sẽ không sửa đổi dòng mới của dòng cuối cùng trong tệp, do đó, đối với một tệp đầu vào có số lượng dòng lẻ như
KEY 4048:1736 string
3
KEY 0:1772 string
paste
sẽ không xử lý ký tự phân tách ở dòng cuối cùng:
$ paste -s -d ',\n' infile
KEY 4048:1736 string,3
KEY 0:1772 string
Bạn cũng có thể sử dụng lệnh vi sau:
:%g/.*/j
nawk '$0 ~ /string$/ {printf "%s ",$0; getline; printf "%s\n", $0}' filename
Cái này đọc là
$0 ~ /string$/ ## matches any lines that end with the Word string
printf ## so print the first line without newline
getline ## get the next line
printf "%s\n" ## print the whole line and carriage return
Một giải pháp khác sử dụng vim (chỉ để tham khảo).
Giải pháp 1:
Mở tệp trong vim vim filename
, sau đó thực thi lệnh :% normal Jj
Lệnh này được bỏ dễ hiểu:
Sau đó, lưu tệp và thoát bằng :wq
Giải pháp 2:
Thực hiện lệnh trong Shell, vim -c ":% normal Jj" filename
, sau đó lưu tệp và thoát bằng :wq
.
Trong trường hợp tôi cần kết hợp hai dòng (để xử lý dễ dàng hơn), nhưng cho phép dữ liệu vượt quá mức cụ thể, tôi thấy điều này hữu ích
data.txt
string1=x
string2=y
string3
string4
cat data.txt | nawk '$0 ~ /string1=/ { printf "%s ", $0; getline; printf "%s\n", $0; getline } { print }' > converted_data.txt
đầu ra sau đó trông như:
convert_data.txt
string1=x string2=y
string3
string4
Cách đơn giản nhất là ở đây:
sed '0~2d' file > 1 && sed '1~2d' file > 2 && paste -d " " 1 2
Perl -0pE 's{^KEY.*?\K\s+(\d+)$}{ $1}msg;' data.txt > data_merged-lines.txt
-0
ngấu nghiến toàn bộ tập tin thay vì đọc từng dòng một;
[.__.] pE
bọc mã bằng vòng lặp và in kết quả đầu ra, xem chi tiết trong http://perldoc.Perl.org/perlrun.html ;
[.__.] ^KEY
khớp "KEY" ở đầu dòng, theo sau là kết hợp không tham lam của bất cứ thứ gì (.*?
) trước chuỗi
\s+
thuộc bất kỳ loại nào kể cả ngắt dòng;(\d+)
mà chúng tôi chụp và sau đó chèn lại dưới dạng $1
;theo sau là cuối dòng $
.
\K
thuận tiện loại trừ mọi thứ ở phía bên trái của nó khỏi sự thay thế, vì vậy { $1}
chỉ thay thế 1-2 chuỗi, xem http://perldoc.Perl.org/perlre.html .
Một giải pháp tổng quát hơn (cho phép nhiều hơn một dòng tiếp theo được tham gia) dưới dạng tập lệnh Shell. Điều này thêm một dòng giữa mỗi, bởi vì tôi cần tầm nhìn, nhưng điều đó dễ dàng được khắc phục. Ví dụ này là nơi dòng "chìa khóa" kết thúc: và không có dòng nào khác làm được.
#!/bin/bash
#
# join "The rest of the story" when the first line of each story
# matches $PATTERN
# Nice for looking for specific changes in bart output
#
PATTERN='*:';
LINEOUT=""
while read line; do
case $line in
$PATTERN)
echo ""
echo $LINEOUT
LINEOUT="$line"
;;
"")
LINEOUT=""
echo ""
;;
*) LINEOUT="$LINEOUT $line"
;;
esac
done