Biểu tượng lạ này có nghĩa là gì:> trong bash có nghĩa là gì


47

Tôi tìm thấy một cái gì đó trong một kịch bản, nhưng không thuộc về kịch bản chính. Có :>một hàng.

Bạn có thể giải thích cho tôi ý nghĩa của nó?

:> file
while read A B C D E; do echo "$A;$B;$D;$E;$C" >> file; done < otherfile

6
Điều quan trọng, :>không phải là một toán tử duy nhất. Nó có thể dễ hiểu hơn nếu bạn đọc nó như là : > filethay vào đó.
jpfx1342

Điều đó có nghĩa là người viết kịch bản nên đã chuyển hướng đầu ra của vòng lặp đến tệp : while read A B C D E; do echo "$A;$B;$D;$E;$C"; done < otherfile > file. Hoặc tốt hơn nữa, lẽ ra họ nên sử dụng công cụ phù hợp cho công việc, awk, theo đề xuất của Peter . Như một bên, bạn hầu như luôn muốn sử dụng -rchuyển đổi vớiread .
Tom Fenech

Bash bên ngoài, nó sẽ là một nụ cười cho một con quạ.
smci

Câu trả lời:


46

Có:> trong một dòng kịch bản bash. Nó có nghĩa là gì?

:> file

Đó là một cách nói ngắn gọn:

  • Nếu filekhông tồn tại thì tạo nó khác cắt nó thành 0byte.

Điều này có nghĩa là bạn có thể chắc chắn rằng nó filetồn tại và nó trống rỗng.

Bạn cũng có thể sử dụng > filenhưng :> filedi động hơn.

Xem câu hỏi về Stack Overflow Mục đích của ':' (dấu hai chấm) GNU Bash Buildin là gì? để biết thêm thông tin.


Tôi không hiểu dòng thứ hai. Tôi nghĩ rằng, đọc các biến đọc. Lệnh echo cũng lạ. Bạn có thể giải thích?
diego9403

Tôi không phải là chuyên gia về Unix nhưng tôi nghĩ dòng thứ hai đọc những thứ từ đó otherfileechochúng ra file. Nó cũng tạo ra các biến từ bất cứ thứ gì nó đọc ... Nếu bạn muốn có một câu trả lời chắc chắn, hãy hỏi câu hỏi của riêng bạn.
DavidPostill

2
@ diego9403: readnhận đầu vào từ stdin. Trên chính nó, nó sẽ đọc những gì bạn gõ. Vì stdin đã được chuyển hướng đến <otherfilenên nội dung của otherfile"được gõ" vào stdin. Vì vậy, readnhận các giá trị từng dòng một vào các biến $ A, $ B, $ C, $ D và $ E.
slebetman

Vì vậy, nó chỉ là một thay thế tối nghĩa hơn truncatetừ coreutils?
Federico Poloni

1
@PeterCordes Tôi không có nghĩa là "tối nghĩa" như trong "nó không phổ biến", nhưng như trong "nó không rõ ràng cho người đọc".
Federico Poloni

29

Nó trông giống như một cách ưa thích để tạo một tập tin mới. Trong bash :là một lệnh null:

$ type : 
: is a shell builtin 
$ help : 
:: :
    Null command.

    No effect; the command does nothing.

    Exit Status:
    Always succeeds.

>chuyển hướng đầu ra của :một tập tin.


2
Nó cũng sẽ cắt bớt tập tin nếu nó đã tồn tại ...
DavidPostill

2
vâng, đây là những gì >làm
Arkadiusz Drabchot

2
:là tốc ký cho true. Có thể trong một số vỏ, truekhông phải là một nội dung? Cả hai đều được tích hợp sẵn trong bash.
Peter Cordes

12

:là một tên khác cho true. Cả hai đều được tích hợp sẵn trong bash, nhưng không /bin/:, chỉ có một /bin/true. Chuyển hướng đầu ra gây ra shell cho open(2)tập tin với O_CREAT|O_TRUNC. Nếu không có gì được viết, nó vẫn ở độ dài bằng không.

Đặt hai mảnh đó lại với nhau, :> filelà một thành ngữ khá phổ biến để cắt bớt các tệp. : >fileMặc dù vậy, hầu hết mọi người sẽ cố gắng làm cho nó trông bớt kỳ lạ hơn bằng cách viết .


Vì bạn đã hỏi trong một nhận xét về dòng thứ 2, tôi sẽ biến nhận xét của mình thành câu trả lời. (mặc dù bạn không hỏi điều này trong câu hỏi của bạn.)

Dòng thứ 2 là một vòng lặp đọc các dòng từ otherfilemột số biến được đặt tên. Phần thân vòng lặp sử dụng echođể in chúng bằng các ;dấu phân cách thay vì bất kỳ khoảng trắng nào trước đây chúng có. fileđược đóng và mở lại (để nối thêm) mỗi lần lặp, bởi vì chuyển hướng nằm trong vòng lặp. Sử dụng while ...;do read -r ...;done <otherfile >filesẽ hút ít hơn và tránh phải cắt bớt tệp trước. read -rkhông ăn \như một nhân vật thoát.

Xử lý văn bản trong bash khá chậm. Một phần của điều đó là không thể tránh khỏi: readphải thực hiện một byte mỗi lần (một read(2)cuộc gọi hệ thống trên mỗi byte) để tránh làm quá mức ở cuối dòng. Sẽ tốt hơn nếu sử dụng đúng công cụ cho công việc:

awk -vOFS=';' '{ print $1, $2, $4, $5, $3 }' -- otherfile  >file

--có nghĩa là kịch bản của bạn không bị hỏng nếu otherfileđược đặt tên như một cái gì đó ngớ ngẩn --version.

Đặt Dấu tách trường đầu ra thành ;nghĩa là bạn chỉ có thể chuyển nhiều trường dưới dạng đối số để in. Shell readchỉ định toàn bộ phần còn lại của dòng có khoảng trắng cho biến cuối cùng, nhưng không có cách nào để nói awk chỉ tách thành 5. Nếu điều đó quan trọng, có thể chỉ cần tiếp tục sử dụng vòng lặp bash, vì nó bất tiện trong awk. Perl làm cho điều này trở nên dễ dàng, vì nó splitcó thể lấy một trường tối đa, nhưng khởi động chậm hơn rất nhiều so với awk.

Trên thực tế, hóa ra nó không khó lắm, chỉ là một regex xấu xí để viết. Để có được phần còn lại thay vì $5trong awk, việc lặp qua các trường vẫn mất khoảng trắng ban đầu của chúng. Ý tưởng khả thi đầu tiên của tôi là sử dụng gensubtrên $0(toàn bộ dòng) để xóa 4 trường đầu tiên (nghĩa là không phải không gian theo sau là khoảng trắng), để lại mọi thứ khác:

awk -vOFS=';' '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1); print $1, $2, $4, tail, $3 }' -- otherfile >file

Tôi đã hiểu đúng ngay từ lần thử đầu tiên, nhưng thực tế là tôi rất ấn tượng với bản thân vì điều đó nói lên điều gì đó về tính dễ đọc của mã awk đó. >. <

Lưu ý cách nó giống printnhư trước đây, nhưng tailthay cho $5.

echo 'A  B c DD    e      f g    f' | 
  awk -vOFS=\; '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1);
   print $1, $2, $4, tail, $3 }'

A;B;DD;e       f g    f;c

Điều này sẽ ấn tượng hơn nếu tôi có thể sao chép / dán nghĩa đen và cho thấy rằng nó đã đi qua trong đầu ra. Nhập một trong bash với ^ Q. ctrl-Q có nghĩa là Trích dẫn phím nhấn tiếp theo dưới dạng ký tự chữ, vì chỉnh sửa dòng kiểu emacs của bash giống như các biểu tượng thực tế cho việc này.

http://mywiki.wooledge.org/BashFAQ có một số nội dung hữu ích về cách viết kịch bản theo những cách sẽ không phá vỡ bất kể dữ liệu hoặc tên tệp nào bạn ném vào tập lệnh.

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.