Ổn định API Unix stdin / stdout API ổn định như thế nào?


20

grepping, awking, spping và đường ống là thói quen hàng ngày của người dùng bất kỳ hệ điều hành nào giống Unix, có thể là trên dòng lệnh hoặc bên trong tập lệnh shell (gọi chung là các bộ lọc từ bây giờ).

Về bản chất, khi làm việc với các chương trình Unix CLI "chuẩn" và các phần tử shell (gọi chung là các lệnh từ bây giờ), các bộ lọc cần một định dạng dự kiến ​​chính xác cho stdin, stdout và stderr trong mỗi bước của bộ lọc để hoạt động chính xác. Tôi gọi định dạng dự kiến ​​chính xác này của một số lệnh là API của lệnh này trong phần sau.

Là một người có nền tảng phát triển web, tôi so sánh loại thu thập dữ liệu và xử lý dữ liệu này với kỹ thuật quét web - một kỹ thuật rất không ổn định mỗi khi có sự thay đổi nhỏ nhất trong cách trình bày dữ liệu.

Câu hỏi của tôi bây giờ liên quan đến sự ổn định của API lệnh Unix.

  1. Các lệnh trong một hệ điều hành giống Unix có tuân thủ tiêu chuẩn hóa chính thức liên quan đến đầu vào và đầu ra của chúng không?
  2. Đã có trường hợp nào trong lịch sử cập nhật một số lệnh quan trọng gây ra phá vỡ chức năng của một số bộ lọc được xây dựng bằng phiên bản cũ hơn của lệnh đã nói chưa?
  3. Các lệnh Unix đã trưởng thành theo thời gian mà hoàn toàn không thể thay đổi theo cách mà một số bộ lọc có thể phá vỡ?
  4. Trong trường hợp bộ lọc có thể bị hỏng theo thời gian do thay đổi API lệnh, làm cách nào tôi có thể là nhà phát triển bảo vệ bộ lọc của mình trước vấn đề này?

Câu trả lời:


17

Tiêu chuẩn POSIX 2008 có một phần mô tả "Shell và tiện ích" . Nói chung, nếu bạn cho rằng các tập lệnh của bạn sẽ khá bằng chứng trong tương lai, ngoại trừ có thể là sự phản đối, nhưng những điều đó hầu như không xảy ra trong một đêm, do đó bạn nên có nhiều thời gian để cập nhật tập lệnh của mình.

Trong một số trường hợp định dạng đầu ra cho một tiện ích khác nhau giữa các nền tảng và phiên bản, tiêu chuẩn POSIX có thể bao gồm một tùy chọn thường được gọi là -p hoặc -Pchỉ định định dạng đầu ra được bảo đảm và có thể dự đoán được. Một ví dụ về điều này là timetiện ích , có nhiều triển khai khác nhau. Nếu bạn cần một định dạng API / đầu ra ổn định, bạn sẽ sử dụng time -p.

Nếu bạn cần sử dụng một tiện ích bộ lọc không được bao phủ bởi tiêu chuẩn POSIX, thì bạn sẽ phải chịu sự thương xót của các nhà đóng gói phân phối / nhà phát triển ngược dòng, giống như bạn đang thương xót các nhà phát triển web từ xa khi thực hiện quét web.


12

Tôi sẽ cố gắng trả lời từ kinh nghiệm của tôi.

  1. Các lệnh không thực sự tuân thủ một đặc tả chính thức, nhưng chúng tuân thủ một yêu cầu để tiêu thụ và tạo văn bản hướng dòng.

  2. Phải, tất nhiên. Trước khi các tiện ích GNU trở thành một tiêu chuẩn thực tế, rất nhiều nhà cung cấp sẽ có đầu ra kỳ quặc, đặc biệt là đối vớipsls. Điều này gây ra rất nhiều đau đớn. Ngày nay, chỉ có HP cung cấp các lệnh siêu kỳ quặc. Trong lịch sử, các tiện ích phân phối phần mềm Berkeley (BSD) là một bước đột phá lớn trong quá khứ. Đặc tả POSIX là một sự phá vỡ với quá khứ, nhưng bây giờ nó được chấp nhận rộng rãi.

  3. Các lệnh Unix đã thực sự trưởng thành theo thời gian. Vẫn không thể phá vỡ một số kịch bản được viết cho một phiên bản cũ hơn. Hãy nghĩ về xu hướng gần đây đối với UTF-8 dưới dạng mã hóa tệp văn bản. Thay đổi này đòi hỏi phải thay đổi các tiện ích cơ bản như tr. Trước đây, văn bản đơn giản hầu như luôn luôn là ASCII (hoặc một cái gì đó gần gũi), vì vậy các chữ cái viết hoa tạo thành một phạm vi số, cũng như các chữ cái viết thường. Điều đó không còn đúng với UTF-8, vì vậytr phải chấp nhận các tùy chọn dòng lệnh khác nhau để chỉ định những thứ như "chữ hoa" hoặc "chữ số".

  4. Một trong những cách tốt nhất để "tăng cường" các bộ lọc của bạn là không phụ thuộc vào bố cục văn bản cụ thể. Ví dụ: không làm cut -c10-24, điều này phụ thuộc vào vị trí của một dòng. Sử dụng cut -f2thay thế, sẽ cắt ra trường thứ 2, tách tab. awkphá vỡ bất kỳ dòng đầu vào nào thành $ 1, $ 2, $ 3 ... là khoảng trắng được phân tách theo mặc định. Phụ thuộc vào các khái niệm cấp cao hơn như "trường" thay vì khái niệm cấp thấp hơn như vị trí cột. Ngoài ra, sử dụng biểu thức chính quy: sedawkcả hai có thể thực hiện mọi việc với biểu thức chính quy không quan tâm đến một số phương sai trong đầu vào. Một mẹo khác là xử lý đầu vào thành một cái gì đó có định dạng mà bộ lọc của bạn có thể kén chọn. Sử dụng tr -cs '[a-zA-z0-9]' '[\n]'để ngắt văn bản thành một từ duy nhất trên mỗi dòng, không có dấu chấm câu. Bạn chỉ không '


9

Đầu tiên, câu trả lời rất ngắn gọn cho câu hỏi của bạn:

  1. Tiêu chuẩn hóa chính thức của các quy ước đầu vào / đầu ra: không
  2. Phá vỡ trong quá khứ do đầu ra thay đổi:
  3. Hoàn toàn không thể phá vỡ các bộ lọc trong tương lai: không
  4. Làm thế nào tôi có thể tự bảo vệ mình trước những thay đổi: hãy bảo thủ

Khi bạn nói "API", bạn đang sử dụng thuật ngữ (tốt hoặc xấu) hàm ý quá nhiều về hình thức xung quanh các quy ước đầu vào / đầu ra của bộ lọc. Rất (và tôi có nghĩa là "rất"), các quy ước chính cho dữ liệu có thể lọc dễ dàng là

  • mỗi dòng đầu vào là một bản ghi đầy đủ
  • trong mỗi bản ghi, các trường được phân tách bằng ký tự dấu phân cách đã biết

Một ví dụ cổ điển sẽ là định dạng của / etc / passwd. Nhưng, những quy ước mặc định này có thể bị vi phạm ở một mức độ nào đó thường xuyên hơn so với việc chúng được tuân theo bức thư.

  • Có rất nhiều bộ lọc (thường được viết bằng awk hoặc perl) phân tích các định dạng đầu vào đa dòng.
  • Có rất nhiều mẫu đầu vào (ví dụ: / var / log / message) trong đó không có cấu trúc trường được xác định rõ và phải sử dụng các kỹ thuật dựa trên biểu thức chính quy chung hơn.

Câu hỏi thứ tư của bạn, làm thế nào để bảo vệ bản thân trước các biến thể trong cấu trúc đầu ra, thực sự là câu hỏi duy nhất mà bạn có thể làm bất cứ điều gì.

  • Như @ jw013 đã nói , hãy nhìn vào những gì các tiêu chuẩn posix nói. Tất nhiên, posix không chỉ định tất cả các lệnh bạn sẽ muốn sử dụng làm nguồn đầu vào.
  • Nếu bạn muốn các tập lệnh của mình có thể mang theo được, hãy cố gắng tránh các đặc điểm riêng của bất kỳ phiên bản nào của một số lệnh mà bạn tình cờ đã bị hủy bỏ. Ví dụ, nhiều phiên bản GNU của lệnh unix tiêu chuẩn có phần mở rộng không chuẩn. Đây có thể là hữu ích, nhưng bạn nên tránh chúng nếu bạn muốn tính di động tối đa.
  • Cố gắng tìm hiểu tập hợp con nào của các đối số lệnh và định dạng đầu ra có xu hướng ổn định trên các nền tảng. Thật không may, điều này đòi hỏi quyền truy cập vào nhiều nền tảng cùng với thời gian, bởi vì những khác biệt này sẽ không được ghi lại ở bất cứ đâu, thậm chí không chính thức.

Cuối cùng, bạn không thể tự bảo vệ mình hoàn toàn khỏi những vấn đề bạn lo lắng và không có nơi nào để tìm kiếm một tuyên bố "dứt khoát" về những gì một lệnh nhất định nên làm. Đối với nhiều tập lệnh shell, đặc biệt là các tập lệnh được viết cho mục đích cá nhân hoặc quy mô nhỏ, điều này đơn giản không phải là vấn đề


5

Chỉ bao gồm 1) câu hỏi của bạn.

API tự nhiên luôn có thể thay đổi theo ý muốn của người tạo và do đó phá vỡ phần mềm phụ thuộc, bằng bất kỳ ngôn ngữ nào. Điều đó nói rằng, ý tưởng tuyệt vời của "API" I / O của các công cụ Unix là thực tế không có (có thể 0x0alà đầu cuối dòng). Một tập lệnh tốt lọc dữ liệu bằng các công cụ Unix thay vì tạo nó. Điều đó có nghĩa là tập lệnh của bạn có thể bị hỏng do thông số đầu vào hoặc đầu ra thay đổi, nhưng không phải do định dạng I / O (một lần nữa, thực sự không phải là một) công cụ riêng lẻ được sử dụng trong tập lệnh đã thay đổi (vì thứ gì đó không thực sự tồn tại không thể thực sự thay đổi).

Đi qua một danh sách các công cụ cơ bản, có một số ít mà tôi cũng thuộc tính nhà sản xuất , trái ngược với chỉ bộ lọc:

  • wc - in số byte, từ, dòng - định dạng rất đơn giản, do đó hoàn toàn không có khả năng thay đổi, và hơn nữa không có khả năng được sử dụng trong tập lệnh.
  • khác biệt - đã phát triển các định dạng đầu ra khác nhau nhưng tôi không nghe thấy bất kỳ vấn đề nào. Cũng không thường được sử dụng mà không có sự giám sát.
  • ngày - Bây giờ ở đây chúng tôi thực sự phải quan tâm những gì chúng tôi sản xuất, đặc biệt là liên quan đến ngôn ngữ hệ thống. Nhưng nếu không, định dạng đầu ra là RFC'ed do bạn không tự xác định chính xác.
  • cal - chúng ta đừng nói về nó, tôi biết rằng định dạng đầu ra không khác nhau nhiều giữa các hệ thống.
  • ls , who , w , last - Tôi không thể giúp nếu bạn muốn phân tích ls, nó không có nghĩa là gì. Ngoài ra, ai, w, cuối cùng, là những người nghe tương tác nhiều hơn; Nếu bạn sử dụng chúng trong một kịch bản, bạn phải quan tâm những gì bạn làm.
  • thời gian đã được chỉ ra trong một bài khác. Nhưng vâng, nó giống như với ls. Thêm để sử dụng tương tác / địa phương. Và bash dựng sẵn rất khác với phiên bản GNU và phiên bản GNU đã có các lỗi không được trộn trong nhiều năm. Đừng dựa vào nó.

Dưới đây là các công cụ mong đợi một định dạng đầu vào cụ thể cụ thể hơn là một luồng byte:

  • bc , dc - máy tính. Đã ở khía cạnh hackish hơn của mọi thứ (thực sự, tôi không sử dụng chúng trong các tập lệnh), và có lẽ các định dạng I / O rất ổn định.

Có một khu vực khác có nguy cơ bị phá vỡ cao hơn nhiều, đó là giao diện dòng lệnh. Hầu hết các công cụ có các tính năng khác nhau cả trên các hệ thống và trên dòng thời gian. Ví dụ là

  • Tất cả các công cụ sử dụng regex - regex có thể thay đổi ý nghĩa dựa trên ngôn ngữ hệ thống (ví dụ LC_COLLATE) và có nhiều sự tinh tế và phân tử trong quá trình triển khai regex.
  • Đơn giản là đừng sử dụng các công tắc ưa thích. Bạn có thể dễ dàng sử dụng man 1p find, ví dụ, để đọc POSIX find manpage thay vì manpage hệ thống. Trên hệ thống của tôi, tôi cần cài đặt manpages-posix.

Và ngay cả khi sử dụng các công tắc như vậy, thông thường sẽ không có lỗi nào được giới thiệu một cách tinh tế và làm độc hại dữ liệu của bạn. Hầu hết các chương trình sẽ chỉ từ chối làm việc với một chuyển đổi không xác định.

Để kết luận, tôi sẽ nói rằng shell thực sự có tiềm năng trở thành một trong những ngôn ngữ di động nhất (nó có thể di động khi bạn viết kịch bản một cách hợp lý). So sánh với các ngôn ngữ kịch bản yêu thích của bạn, nơi xảy ra lỗi tinh vi hoặc chương trình biên dịch yêu thích của bạn sẽ được biên dịch.

Ngoài ra, tại những nơi hiếm hoi có thể xảy ra sự cố do không tương thích, có thể không phải do thời gian gây ra mà do sự đa dạng trên các hệ thống khác nhau (có nghĩa là nếu nó hoạt động cho bạn, nó đã làm như vậy 20 năm trước và sẽ trong 20 năm , quá). Đó là một hệ quả của sự đơn giản của các công cụ.


1

Chỉ có các tiêu chuẩn IO trên thực tế - khoảng trắng và đầu ra tách biệt null.

Về tính tương thích, chúng tôi thường hoàn nguyên để kiểm tra số phiên bản của các bộ lọc riêng lẻ. Không phải họ thay đổi nhiều, nhưng khi bạn muốn sử dụng một tính năng hoàn toàn mới và vẫn muốn tập lệnh chạy trên các phiên bản cũ hơn, bạn phải "ifdef" bằng cách nào đó. Thực tế không có cơ chế báo cáo khả năng, lưu để viết các trường hợp kiểm tra bằng tay.


0

Các kịch bản bị phá vỡ, một số thường xuyên hơn so với những người khác. Phần mềm cũ và nổi tiếng có xu hướng giữ nguyên, và thường có các cờ tương thích khi nó thay đổi.

Các tập lệnh được viết trên một hệ thống có xu hướng tiếp tục hoạt động, nhưng thường phá vỡ một tập lệnh khác.

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.