Cách để xóa dòng mới (^ M) khỏi các biến, không phải từ tệp


8

Tôi đang tải một tệp vào các biến, vấn đề là tệp được định dạng trong Windows, tôi tin, vì vậy tôi nhận được một ^Mthay vì một dòng mới.

Làm cách nào để sửa đổi nó khi giá trị nằm trong biến? Tôi biết rằng tôi có thể sửa đổi nguồn trong VI (bằng cách này, tôi sử dụng OS X), nhưng tôi không thể sửa đổi tệp gốc, chỉ đọc nó, vì vậy tôi phải xóa ^Mkhỏi biến.

Theo hiểu biết của tôi, \nkhông giống như ^M, vì vậy trlệnh sẽ không hoạt động.

BIÊN TẬP

Có vẻ như câu hỏi không rõ ràng; Vì vậy, đây là sự làm rõ.

Tôi phân tích từng dòng tập tin; mỗi dòng có 2 giá trị, được phân tách bằng tab và ở cuối mỗi dòng, có một ^ M, nó trông như thế này:

value1    value2^M
value3    value4^M
value5    value6^M
value7    value8^M

Quy trình làm việc của tôi khá đơn giản và đơn giản: tệp txt chứa những gì bạn thấy ở trên, các trường riêng biệt của vòng lặp và cho mỗi dòng nhận các giá trị; Khi tôi in giá trị thứ hai, nó có ^ M, mà tôi muốn xóa

while IFS=$'\t' read -r -a line
do
    Type1="${line[0]}"
    Type2="${line[1]}"
done < $TXTFILE

Có nghĩa là khi tôi in Type1 thì không sao, nhưng biến Type2 chứa ^ M. Tôi đã sử dụng trvà nó không hoạt động, tôi đã sử dụng sedđể loại bỏ ký tự cuối cùng của biến và nó không hoạt động. Hy vọng điều này làm rõ câu hỏi của tôi. Cảm ơn


1
Làm thế nào bạn đọc các tập tin thành biến? có thể có thể xóa nó trong thời gian đó ... ví dụ: sử dụng sed 's|\r||' filethay vìfile
Sundeep

Tôi sẽ trả lời trnhưng câu hỏi là cách để mở rộng. Chúng tôi không biết đầu vào hoặc đầu ra là gì, cũng như kịch bản trông như thế nào.
Julie Pelletier

Tôi đã thêm thông tin vào câu hỏi; Tôi tải tệp với vòng lặp tiêu chuẩn trong bash, thay đổi IFS thành tab, vì vậy tôi có thể chia dòng thành 2 phần và nhận 2 biến. Tôi đã thử TR nhưng nó không hoạt động, tương tự cho sed; đó là lý do tại sao tôi đã đi trước và đăng câu hỏi ở đây. Cảm ơn
rataplan

Tôi thấy lạ khi bạn chấp nhận một giải pháp phức tạp không cần thiết. Bạn đã thử của tôi?
jlliagre

Câu trả lời:


9

^Mlà lợi nhuận vận chuyển (CR), có thể được chỉ định như \rcho trhoặc bên trong $'…'. \nchỉ định một nguồn cấp dữ liệu (LF), đó là ^J. Một dòng kết thúc Unix là LF và một dấu tách dòng Windows là chuỗi CR-LF gồm hai ký tự, do đó, các tệp văn bản Windows được xem trong một hệ thống Unix như Linux hoặc macOS trông giống như ^Mở cuối mỗi dòng ngoại trừ dòng cuối cùng dòng đang thiếu dòng mới cuối cùng của nó.

Bạn có thể xóa trả lại vận chuyển từ một tệp trvới

tr -d '\r' <somefile.txt >somefile.txt.new && mv somefile.txt.new somefile.txt

hoặc đơn giản hơn với dos2unix.

Để tránh sửa đổi các tệp, bạn có thể kiểm tra từng dòng khi bạn đọc nó và tách CR ở cuối dòng. Ví dụ: nếu bạn đang sử dụng readđể phân tích các giá trị được phân tách bằng tab, thì hãy tách CR ở cuối trường cuối cùng. Việc mở rộng tham số ${VAR%$'\r'}mang lại giá trị VARtrừ đi một CR kéo dài và mang lại giá trị VARnếu nó không kết thúc với CR.

while IFS=$'\t' read -r -a line
do
    line[$((${#line[@]}-1))]="${line[$((${#line[@]}-1))]%$'\r'}"
    Type1="${line[0]}"
    Type2="${line[1]}"
done < "$TXTFILE"

Cảm ơn đã làm rõ rằng / r trên thực tế giống như ^ M; giải pháp hoạt động
rataplan

Lưu ý rằng OS / X đi kèm với một phiên bản rất cũ bash, vì vậy tôi không hy vọng nó sẽ hỗ trợ line[-1]cho bạn cần bash-4.3 trở lên. Nó đi kèm với zshnó hỗ trợ nó (và đã trong nhiều thập kỷ), nhưng lưu ý rằng trong zsh, phần tử đầu tiên là $line[1], không $line[0](trừ khi trong mô phỏng ksh). Với phiên bản cũ hơn bash, bạn luôn có thể sử dụngline[${#line[@]}-1]
Stéphane Chazelas

+1 cho giải thích nền, nhưng tôi nghĩ giải pháp của jiliagre tốt hơn nhiều, và đơn giản hơn nhiều .
tự đại diện

7

Dưới đây là cách đơn giản nhất để sửa tập lệnh của bạn, chỉ cần thêm "trả lại vận chuyển" làm dấu tách trường nội bộ cho lệnh đọc:

trong khi IFS = $ '\ t \ r ' đọc -r -a dòng
làm
  Loại1 = "$ {dòng [0]}"
  Loại2 = "$ {dòng [1]}"
đã hoàn thành <$ TXTFILE

1
@jiliagre, vâng, bạn nói đúng, nó được coi là một dấu phân cách ở đó. Điều đó sẽ khác ở zshnơi $IFSđược lấy làm dải phân cách.
Stéphane Chazelas

2
@ StéphaneChazelas Cảm ơn, bạn quá ám ảnh với zsh;-)
jlliagre

4

Sử dụng (đối với chuỗi ngắn):

${var//$'\015'}

Thí dụ:

$ var=$'This is a test of a CR (\r) character'
$ echo "${var//$'\r'}"
This is a test of a CR () character

Đối với chuỗi dài hơn, bạn có thể cần sed hoặc awk.


0

Một cách nói chung hữu ích hơn để chuyển đổi nội dung của các tệp "DOS", không có điểm đánh dấu nội dung nào khác ngoài việc có các kết thúc dòng CR + LF (trái ngược với Linux 'LF).

Đối với Ubuntu, đầu tiên và một lần duy nhất, hãy làm

sudo apt cài đặt dos2unix

việc sử dụng như được chỉ ra dưới đây, ở đây odđược sử dụng để xác minh đầu ra

$ dos2unix <$ TXTFILE | od -t x1z -w17
0000000 76 61 6c 75 65 31 20 20 20 20 76 61 6c 75 65 32 0a> value1 value2. <
0000021 76 61 6c 75 65 33 20 20 20 20 76 61 6c 75 65 34 0a> giá trị3 giá trị4. <
0000042 76 61 6c 75 65 35 20 20 20 20 76 61 6c 75 65 36 0a> giá trị5 giá trị6. <
0000063 76 61 6c 75 65 37 20 20 20 20 76 61 6c 75 65 38 0a> giá trị7 giá trị8. <
0000104

$ mèo $ TXTFILE | od -t x1z -w18
0000000 76 61 6c 75 65 31 20 20 20 20 76 61 6c 75 65 32 0d 0a> value1 value2 .. <
0000022 76 61 6c 75 65 33 20 20 20 20 76 61 6c 75 65 34 0d 0a> value3 value4 .. <
0000044 76 61 6c 75 65 35 20 20 20 20 76 61 6c 75 65 36 0d 0a> giá trị5 giá trị6 .. <
0000066 76 61 6c 75 65 37 20 20 20 20 76 61 6c 75 65 38 0d 0a> value7 value8 .. <
0000110

Điều này sẽ dịch không chỉ các kết thúc dòng mà còn các ký tự đặc biệt khác, tùy thuộc vào các tham số đến dos2unixhoặc đối tác của nó unix2dos(được cài đặt cùng lúc).


Không phải dos2unix ở đó theo mặc định?
phuclv

Tôi đã xác định rõ ràng rằng tôi biết cách thực hiện thông qua sửa đổi tập tin; cộng với tôi không sử dụng linux mà là OSX, vì vậy để cài đặt dos2unix tôi phải sử dụng brew
rataplan

dos2unixkhông CỐ ĐỊNH để sử dụng sửa đổi FILE, nó là "bộ lọc" và có thể được sử dụng trong đường ống; giống như tr. Nó cũng nên được ưu tiên hơn trvì nó xử lý các bộ ký tự ở mức cao hơn, không chỉ các mã byte đơn.
Hannu

@ Lưu Vĩnh Phúc, tôi đang sử dụng Ubuntu 16.04 và có bản cài đặt khá mới và tôi đã phải cài đặt nó.
Hannu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.