Lệnh mèo và tiếng vang


14

Tôi muốn nối đầu ra từ echo với nội dung của tệp. Tôi đã thử các trạng thái sau:

echo "abc" | cat 1.txt > 2.txt

nhưng 2.txttập tin chỉ chứa nội dung từ 1.txt. Tại sao nó không hoạt động?


3
Các chương trình như catchỉ đọc từ đầu vào tiêu chuẩn nếu chúng không có bất kỳ đối số tên tệp nào.
Barmar

Câu trả lời:


23

Nó không hoạt động vì catchương trình trong chuỗi ống của bạn không được hướng dẫn để đọc echođầu ra của chương trình từ đầu vào tiêu chuẩn.

Bạn có thể sử dụng -làm tên tệp giả để chỉ ra đầu vào tiêu chuẩn cat. Từ man catcài đặt msys2:

EXAMPLES
       cat f - g
              Output f's contents, then standard input, then g's contents.

Hãy thử

echo "abc" | cat - 1.txt > 2.txt

thay thế.


21

Như đã lưu ý bởi những người khác, lệnh ban đầu của bạn không thành công vì cat 1.txtbỏ qua đầu vào tiêu chuẩn của nó. Hoặc chỉ ra rằng nó phải là đối số đầu tiên của nó ( cat - 1.txt) hoặc sử dụng chuyển hướng khối để chuyển hướng echo abc cat 1.txt cùng nhau. Để dí dỏm:

{ echo abc; cat 1.txt; } > 2.txt 

Đoạn trích liên quan từ hướng dẫn ( man bash):

Lệnh Compound Lệnh
ghép là một trong những lệnh sau. Trong hầu hết các trường hợp, một danh sách trong mô tả của lệnh có thể được tách biệt với phần còn lại của lệnh bằng một hoặc nhiều dòng mới và có thể được theo sau bởi một dòng mới thay cho dấu chấm phẩy.

(danh sách)

    danh sách được thực thi trong môi trường mạng con (xem MÔI TRƯỜNG THỰC HIỆN QUY TẮC bên dưới). Các phép gán biến và các lệnh dựng sẵn ảnh hưởng đến môi trường của shell không còn hiệu lực sau khi lệnh hoàn thành. Trạng thái trả về là trạng thái thoát của danh sách.

{danh sách; }

    danh sách được thực hiện đơn giản trong môi trường shell hiện tại.  danh sách phải được chấm dứt bằng một dòng mới hoặc dấu chấm phẩy. Điều này được gọi là một lệnh nhóm . Trạng thái trả về là trạng thái thoát của danh sách . Lưu ý rằng không giống như các ký tự đại diện (), {}là các từ dành riêng và phải xảy ra khi một từ dành riêng được phép được công nhận. Vì chúng không gây ra ngắt từ, chúng phải được tách ra khỏi danh sách bằng khoảng trắng hoặc metacharacter vỏ khác.

Tùy chọn đầu tiên (môi trường subshell) có một loạt các tác dụng phụ, hầu hết nếu không phải tất cả đều không liên quan đến kịch bản của bạn; tuy nhiên, nếu chuyển hướng một loạt các đầu ra của lệnh là tất cả những gì bạn cần, thì Tùy chọn # 2 ở đây (lệnh nhóm) được ưu tiên.


7
( echo "abc"; cat 1.txt ) > 2.txt

Bạn đã chuyển đầu ra echo thành cat, nhưng cat không sử dụng được đầu vào và bỏ qua nó. Bây giờ các lệnh chạy lần lượt từng cái và đầu ra của chúng được nhóm lại (dấu ngoặc đơn) và được hướng vào 2.txt.


1
Câu trả lời này có thể được cải thiện bằng cách giải thích cách thức hoạt động và lý do tại sao nỗ lực ban đầu của OP không hoạt động.
Bob

OK, hãy thử xem.
Gerard H. Pille

5
Một subshell không được yêu cầu rõ ràng ở đây, có lẽ sẽ tốt hơn nếu sử dụng lệnh nhóm. Xem câu trả lời của tôi để biết thêm chi tiết.
Nubarke

Ah, nhưng tôi sẽ không bao giờ sử dụng bash.
Gerard H. Pille

1
@ GerardH.Pille: Trong khi câu trả lời của Daniel trích dẫn từ bash(1), nó mô tả hành vi mà mọi vỏ tuân thủ POSIX phải hỗ trợ.
G-Man nói 'Phục hồi Monica'

2

Lệnh của bạn cat 1.txtkhông làm gì với đầu ra của echo "abc".

Thay vào đó: (echo "abc"; cat 1.txt) > 2.txt sẽ ghi đầu ra của cả hai lệnh vào 2.txt.


Câu trả lời này có thể được cải thiện bằng cách giải thích cách thức thay thế được đề xuất hoạt động.
Bob

1

Trong bất kỳ shell POSIX nào, bạn có thể sử dụng thay thế lệnh để sử dụng cat filelàm đầu vào cho echo:

echo $(cat file1.txt) "This Too"

Trong Bash, bạn có thể sử dụng thay thế quá trình và sử dụng echo như một "tệp" khác cat, như trong:

cat file1.txt <(echo This Too)

và sau đó ống hoặc chuyển hướng đầu ra khi bạn thấy phù hợp.

Giống như mọi câu trả lời khác, mèo bỏ qua stdin nếu nó có một tập tin để xem. (Tôi cũng thích câu trả lời của Daniel & mvw, +1 cho họ)


1
Câu trả lời này có thể được cải thiện bằng cách giải thích lý do tại sao nỗ lực ban đầu của OP không hoạt động (và do đó tại sao điều này là cần thiết thay thế).
Bob

1
Việc <(command)xây dựng là một phần mở rộng bash. Nó không phải là POSIX, vì vậy bạn không thể dựa vào nó trong các tập lệnh được cho là được thực thi /bin/sh.
Rhialto hỗ trợ Monica

0

Chỉ là một phỏng đoán, nhưng có vẻ như bạn có một quy trình lặp lại, đó là một ứng cử viên tốt cho bí danh hoặc chức năng. Các bí danh thường là các đoạn cắt ngắn để gọi các lệnh bash, chẳng hạn như viết tắt, trên một luồng đầu vào dưới dạng đối số / s của nó.

alias hg="history | grep"

Tuy nhiên, trong trường hợp này, một hàm sẽ dễ đọc hơn, vì bạn đang kết hợp nhiều luồng đầu vào, 2 (rời rạc) cũng như nhiều lệnh bash. Bạn có hai đối số, đầu tiên là một chuỗi và bên kia là một filepath. Cuối cùng, bạn muốn kết quả được ghi vào luồng đầu ra xuất chuẩn.

Từ một dấu nhắc CLI, gõ này:

# ecat()        
{
echo ${1}
cat ${2}
}

Chức năng của bạn được đặt tên là ecat, đó là đáng nhớ.

Bây giờ bạn có thể gọi như

ecat "abc" 1.txt

Để nối thêm, chỉ cần cung cấp đích đầu ra khác cho thiết bị xuất chuẩn:

ecat "abc" 1.txt >> 2.txt

Toán tử chuyển hướng chắp thêm '>>' sẽ thêm đầu ra vào cuối tệp được chỉ định.

Nếu bạn thích nó, sau đó nối vào tệp ~ / .bashrc của bạn để sử dụng lại.

declare -f ecat >> ~/.bashrc

Điều đó cũng có nghĩa là bạn có thể trang trí, vv, trong định nghĩa chức năng của bạn.

Cũng là một ý tưởng tốt để bảo vệ các tệp khỏi bị ghi đè bằng cách thêm tệp này vào ~ / .bashrc của bạn

set noclobber

2
Để chức năng của bạn hoạt động đúng, bạn nên sử dụng "$1""$2". Trong bối cảnh này, niềng răng xoăn không làm gì tốt. Xem ${name}không có nghĩa là những gì bạn nghĩ rằng nó làm .
G-Man nói 'Phục hồi Monica'

1
Làm thế nào là noclobbergợi ý đáp ứng với câu hỏi trong tầm tay? (Tôi cũng không tin lắm rằng đó là lời khuyên tốt - sửa đổi hành vi toàn cầu có xu hướng phá vỡ các kịch bản / lời khuyên / thực tiễn được xây dựng với ý định mặc định).
Charles Duffy

0

Các mã sau đây cũng sẽ hoạt động:

echo abc >> 1.txt && cat 1.txt > 2.txt

Đầu ra của echo abc sẽ được thêm vào 1.txt với >> Sau đó, && sẽ bảo nó chạy bộ lệnh tiếp theo sẽ cat 1.txt và sau đó xuất thành 2.txt . Về cơ bản, nó nối đầu ra của lệnh đầu tiên vào 1.txt và sau đó gửi đầu ra của 1.txt thành 2.txt.

Nếu bạn muốn abc xuất hiện đầu tiên, bạn có thể sử dụng mã sau:

echo abc >> 2.txt && cat 1.txt >> 2.txt

1
Điều này sẽ (1) đặt abcdưới cùng của 2.txt; câu hỏi muốn nó ở đầu (2)  sửa đổi các 1.txttập tin; Điều này là không thể chấp nhận được.
G-Man nói 'Phục hồi Monica'

Nó nói ở đâu? Ringger81 không bao giờ chỉ định nơi 2.txt anh ấy muốn abc xuất hiện. Bạn đang giả định những điều mà câu hỏi không bao giờ nêu.
Nasir Riley

(1) OK, bạn tăng điểm hợp lệ trên # 1. Trong khi các câu hỏi đề cập đến “đầu ra từ echo” trước khi “nội dung của một tập tin” trong văn bản, và sau đó đặt echotrước cattrong lệnh mẫu, tôi giả sử rằng nó không bao giờ chính xác, rõ ràng , nói rằng họ muốn đầu ra từ tiếng vang trước nội dung của tập tin đầu vào. Có vẻ như hầu hết mọi người giải thích nó theo cách đó. (2)  1.txtlà một tập tin đầu vào. Câu hỏi không nói gì về sửa đổi 1.txt. Thực tế là các tập tin đầu vào không nên được sửa đổi mà không cần nói.
G-Man nói 'Phục hồi Monica'

Tôi có thể hiểu quan điểm của bạn về việc không sửa đổi tệp imput. Mã thứ hai của tôi sẽ đạt được hiệu quả mong muốn mà không cần làm như vậy.
Nasir Riley

1
Mở tệp, nối thêm, đóng tệp , mở lại, nối lại ... tại sao lại làm như vậy thay vì chỉ mở một lần và giữ chuyển hướng tại chỗ cho cả hai thao tác?
Charles Duffy
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.