Sử dụng | ký tự ống từ một biến $ làm cho nó coi như là một đối số khác trong bash; Làm thế nào để thoát khỏi nó?


8

Tôi có một kịch bản bash như thế này

export pipedargument="| sort -n"
ls $pipedargument

Nhưng nó cho lỗi

ls: |: No such file or directory
ls: sort: No such file or directory

Nó dường như được coi là nội dung của "| sort -n"chỉ là một đối số được thông qua ls.

Làm thế nào tôi có thể thoát nó để nó được coi là một lệnh đường ống thông thường?

Tôi đang cố gắng đặt điều kiện $pipedargument. Tôi đoán rằng tôi chỉ có thể thực hiện một cách có điều kiện các phiên bản khác nhau của lệnh nhưng vẫn tự hỏi liệu có cách nào để thực hiện công việc này như trên không?

Câu trả lời:


9

Bạn đúng rằng bạn không thể sử dụng |theo cách đó. Lý do là shell đã tìm kiếm các đường ống và tách chúng thành các lệnh trước khi nó thay thế. Do đó, |được coi là một nhân vật khác.

Một cách giải quyết có thể là đặt ký tự ống theo nghĩa đen:

$ cmd="sort -n"
$ ls | $cmd

Trong trường hợp bạn không muốn có một đường ống dẫn, bạn có thể sử dụng catnhư một "nop" hoặc giữ chỗ:

$ cmd=cat
$ ls | $cmd

Phương pháp này tránh sự tinh tế của eval . Xem thêm tại đây .

Một cách tiếp cận tốt hơn: mảng

Một cách tiếp cận tinh vi hơn sẽ sử dụng bashcác mảng thay cho các chuỗi đơn giản:

$ cmd=(sort -n)
$ ls | "${cmd[@]}"

Lợi thế của mảng trở nên quan trọng ngay khi bạn cần lệnh cmdđể chứa các đối số được trích dẫn.


Bạn có thể làm rõ tại sao mảng là cần thiết trong trường hợp đối số được trích dẫn? Tôi chạy vào đó, nhưng không hiểu tại sao nó không hoạt động.
lo lắng

@anxieux Một câu trả lời ngắn gọn là một trích dẫn, khi bên trong chuỗi shell, mất tất cả sức mạnh cú pháp của nó để nhóm các từ và thay vào đó được đối xử như bất kỳ ký tự nào khác. Để thảo luận lâu hơn và xuất sắc về vấn đề này, hãy xem: Tôi đang cố gắng đặt một lệnh trong một biến, nhưng các trường hợp phức tạp luôn thất bại! .
John1024

5

Bạn có thể evaluate lệnh:

eval "ls $pipedargument"

hoặc thậm chí tốt hơn xác định chức năng như:

sorted() { "$@" | sort -n; }

và sau này gọi nó với các đối số mong muốn:

sorted ls /tmp

Một tùy chọn khác là xác định bí danh:alias ls='ls | sort -n'
thiagowfx

0

Tôi sẽ sử dụng một chức năng cho việc này. Cái gì đó như:

### usage pipedargument cmd args ###

pipedargument()
{
    sort -n <<< "$( "$@" )"
}

$ pipedargument /sbin/ifconfig eth0
      RX bytes:5904986765 (5.4 GiB)  TX bytes:714370767 (681.2 MiB)
      RX packets:5981427 errors:0 dropped:0 overruns:0 frame:0
      TX packets:4403989 errors:0 dropped:0 overruns:0 carrier:0
      UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
      collisions:0 txqueuelen:1000 
      inet addr:XXX.XXX.X.XX  Bcast:XXX.XXX.X.XXX  Mask:255.255.255.0
      inet6 addr: xx00::0x0x:00xx:xx0:000/00 Scope:Link
eth0      Link encap:Ethernet  HWaddr 0x:0x:00:x0:00:00
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.