Làm cách nào để loại bỏ \ n giữa các đầu ra của hai lệnh echo?


13

Tôi có một tệp văn bản chứa một tên tệp trong mỗi dòng:

111_c4l5r120.png
123_c4l4r60.png
135_c4l4r180.png
147_c4l3r60.png
15_c4l1r120.png
...

Tôi muốn chuyển đổi nó trong hình dạng này:

111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15
...

sử dụng mã này:

#!/bin/bash
while IFS='' read -r line || [[  -n "$line"  ]]; do
   echo "$line" >> output.txt   
   echo "$line" | cut -d'_' -f 1 >> output.txt
done < "$1"

nhưng, kết quả là:

111_c4l5r120.png 
111
123_c4l4r60.png 
123
135_c4l4r180.png 
135
147_c4l3r60.png 
147
15_c4l1r120.png 
15
...

Làm thế nào tôi nên thay đổi kịch bản của tôi để có đầu ra mong muốn?


Google tìm thấy kết quả tốt hơn, ví dụ, điều này .
Thomas Dickey

Câu trả lời:


17

Trừ khi bạn có nhu cầu cụ thể để sử dụng vỏ cho việc này, câu trả lời của terdon cung cấp các lựa chọn thay thế tốt hơn.

Vì bạn đang sử dụng bash(như được chỉ định trong shebang của tập lệnh), bạn có thể sử dụng -ntùy chọn để lặp lại:

echo -n "${line} " >> output.txt
echo "$line" | cut -d'_' -f 1 >> output.txt

Hoặc bạn có thể sử dụng các tính năng shell để xử lý dòng mà không cần sử dụng cut:

echo "${line} ${line%%_*}" >> output.txt

(thay thế cả hai echodòng).

Ngoài ra, printfcũng sẽ thực hiện thủ thuật này, hoạt động trong bất kỳ vỏ POSIX nào và thường tốt hơn (xem Tại sao printf tốt hơn echo? Để biết chi tiết):

printf "%s " "${line}" >> output.txt
echo "$line" | cut -d'_' -f 1 >> output.txt

hoặc là

printf "%s %s\n" "${line}" "${line%%_*}" >> output.txt

(Nói đúng ra, rõ ràng /bin/sh, echo -nkhông thể mang theo được . Vì bạn rõ ràng sử dụng bashnó ở đây.)


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
terdon

23

Đừng làm điều này trong vỏ! Nó phức tạp hơn nhiều so với cần thiết, dễ bị lỗi và xa, xa, chậm. Có nhiều công cụ được thiết kế để thao tác văn bản như vậy. Ví dụ: trong sed(ở đây giả sử các triển khai GNU hoặc BSD gần đây cho -E):

$ sed -E 's/([^_]*).*/& \1/' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15

Hoặc, cho bất kỳ sed:

$ sed 's/\([^_]*\).*/& \1/' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15

Perl:

$ perl -pe 's/(.+?)_.*/$& $1/' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15

ôi

$ awk -F_ '{print $0,$1}' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15

1
Các tiện ích bên ngoài không tốt hơn nhiều, mặc dù.
EKons

6
@ ΈρκΚω Một số đơn đặt hàng cường độ nhanh hơn, thực sự. Vỏ chỉ là không tốt ở loại điều này. Rốt cuộc, công việc chính của shell là khởi chạy các tiện ích bên ngoài. So sánh thời gian thực hiện theo cách tiếp cận của OP với bất kỳ giải pháp nào được thực hiện ở đây. Các vòng lặp vỏ rất, rất chậm. Nếu bạn cần thuyết phục hơn, hãy đọc .
terdon

Về tính di động, không. Về tốc độ, có. Ngoài ra, @ StéphaneChazelas có phải là bí danh của bạn không?
EKons

4
@ ΈρκΚωστ :) Không, anh ta chỉ tình cờ viết 2 câu trả lời tuyệt vời có liên quan đến hai luồng nhận xét. Về tính di động, ngoại trừ (thứ yếu) của phương pháp perl sẽ chỉ hoạt động trên một cái gì đó giống như ~ 90% máy * nix, cả ba giải pháp đều là bất khả tri di động và vỏ. Hoặc, OK, bạn luôn có thể biến sednó thành sed 's/\([^_]*\).*/& \1/' filemột tính di động bổ sung. Vấn đề là, bạn có thể tin tưởng awksedở đó nhiều hơn bạn có thể tin tưởng vào bất cứ điều gì khác.
terdon

2

Của bạn đây:

#!/bin/bash

while IFS='' read -r line || [[  -n "$line"  ]]; do
   echo "$line" `echo "$line" | cut -d'_' -f 1` >> output.txt
#   echo "$line" | cut -d'_' -f 1 >> output.txt
done < "$1"

Đầu ra:

$ rm -rf output.txt
$ ./test.sh 1.1; cat output.txt
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15
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.