Sự khác biệt giữa chạy lệnh trực tiếp và với `bash -c` là gì?


8

Đối với một lệnh (dựng sẵn hoặc bên ngoài), sự khác biệt của việc chạy nó trực tiếp trong quy trình bash shell và với bash -ctrong bash shell là gì? Ưu điểm và nhược điểm của họ so với nhau là gì?

For example, in a bash shell, run `date` directly, and run `bash -c
date`. Also consider a builtin command instead of an external one.

Câu trả lời:


12
  1. Các -ctùy chọn cho phép các chương trình để các lệnh chạy. Dễ dàng hơn nhiều để rẽ nhánh và làm

    execl("/bin/sh", "sh", "-c", "date | od -cb  &&  ps > ps.out", NULL);

    hơn là để rẽ nhánh, tạo đường ống, ngã ba lần nữa, gọi execltừng đứa trẻ, gọi wait, kiểm tra trạng thái thoát, ngã ba lần nữa, gọi close(1), mở tệp, đảm bảo rằng nó được mở trên mô tả tệp 1 và thực hiện một thao tác khác execl. Tôi tin rằng đây là lý do tại sao tùy chọn được tạo ngay từ đầu.

    Hàm system()thư viện chạy một lệnh theo phương thức trên.

  2. Nó cung cấp một cách để nhận một lệnh phức tạp tùy ý và làm cho nó trông giống như một lệnh đơn giản. Điều này hữu ích với các chương trình chạy lệnh do người dùng chỉ định, chẳng hạn như find … -exechoặc xargs. Nhưng bạn đã biết điều đó; đó là một phần của câu trả lời cho câu hỏi của bạn, Làm thế nào để xác định một lệnh ghép làm đối số cho một lệnh khác?
  3. Nó có thể có ích nếu bạn đang chạy một vỏ tương tác khác ngoài bash. Ngược lại, nếu bạn đang chạy bash, bạn có thể sử dụng cú pháp này

    $ tro -c " lệnh "
                 ︙
     
    $ csh -c " lệnh "
                 ︙
     
    $ dash -c " lệnh "
                 ︙
     
    $ zsh -c " lệnh "
                 ︙

    để chạy một lệnh trong shell khác, vì tất cả các shell đó cũng nhận ra -ctùy chọn. Tất nhiên bạn có thể đạt được kết quả tương tự với

    $ trolệnh 
    tro $
            ︙
    tro $ thoát
     
    $ cshlệnh 
    csh $
            ︙
    csh $ thoát
     
    $ gạch nganglệnh 
    dash $
            ︙
    dấu gạch ngang $ exit
     
    $ zshlệnh 
    zsh $
            ︙
    thoát zsh $

    Tôi đã sử dụng ash$ , vv, để minh họa các lời nhắc từ các shell khác nhau; bạn có thể sẽ không thực sự có được những thứ đó.

  4. Nó có thể có ích nếu bạn muốn chạy một lệnh trong shell bash tươi tươi của Tep; ví dụ,

    $ ls -lA
    total 0
    -rw-r--r-- 1 gman gman   0 Apr 14 20:16 .file1
    -rw-r--r-- 1 gman gman   0 Apr 14 20:16 file2
    
    $ echo *
    file2
    
    $ shopt -s dotglob
    
    $ echo *
    .file1 file2
    
    $ bash -c "echo *"
    file2
    

    hoặc là

    $ type shift
    shift is a shell builtin
    
    $ alias shift=date
    
    $ type shift
    shift is aliased to ‘date’
    
    $ bash -c "type shift"
    shift is a shell builtin
    
  5. Trên đây là một đơn giản hóa quá mức sai lệch. Khi bash được chạy với -c, nó được coi là một vỏ không tương tác và nó không đọc ~/.bashrc, trừ khi được -ichỉ định. Vì thế,

    $ loại cp
    cp được đặt bí danh là 'cp -i'           # Được xác định trong ~ / .bashrc
     
    $ cp .file1 file2
    cp: ghi đè 'file2'? n
     
    $ bash -c "cp .file1 file2"
                                      # Tập tin hiện tại bị ghi đè mà không cần xác nhận!
    $ bash -c -i "cp .file1 file2"
    cp: ghi đè 'file2'? n

    Bạn có thể sử dụng -ci, -i -choặc -icthay vì -c -i.

    Điều này có thể áp dụng ở một mức độ nào đó cho các shell khác được đề cập trong đoạn 3, do đó, dạng dài (nghĩa là dạng thứ hai, thực sự chính xác cùng một lượng gõ) có thể an toàn hơn, đặc biệt là nếu bạn đã thiết lập các tệp cấu hình / khởi tạo cho những cái vỏ.

  6. Như Wildcard đã giải thích , vì bạn đang chạy một cây quy trình mới (một quy trình shell mới và, có khả năng, quá trình con của nó), các thay đổi đối với môi trường được tạo trong lớp con có thể ảnh hưởng đến shell cha (thư mục hiện tại, các giá trị của môi trường các biến, định nghĩa hàm, v.v.) Vì vậy, thật khó để tưởng tượng một lệnh dựng sẵn shell sẽ hữu ích khi chạy bởi sh -c.  fg, bgjobskhông thể ảnh hưởng hoặc truy cập các công việc nền được bắt đầu bởi shell cha, cũng không thể waitchờ chúng.  về cơ bản tương đương với việc chỉ chạy theo cách thông thường, trực tiếp từ vỏ tương tác.  là một sự lãng phí lớn thời gian  vàsh -c "exec some_program"some_programsh -c exitulimitumask có thể thay đổi cài đặt hệ thống cho quy trình con và sau đó thoát mà không thực hiện chúng.

    Chỉ về lệnh dựng sẵn duy nhất có chức năng trong sh -cngữ cảnh là kill. Tất nhiên, các lệnh mà chỉ có sản phẩm đầu ra ( echo, printf, pwdtype) không bị ảnh hưởng, và nếu bạn viết một tập tin, mà sẽ kéo dài.

  7. Tất nhiên bạn có thể sử dụng một dựng sẵn kết hợp với một lệnh bên ngoài; ví dụ,
    sh -c "cd some_directory ; some_program "
    nhưng về cơ bản bạn có thể đạt được hiệu ứng tương tự với một lớp con bình thường:
    (cd some_directory ; some_program )
    cái nào hiệu quả hơn Giống nhau (cả hai phần) có thể được nói cho một cái gì đó như
    sh -c "umask 77; some_program "
    hoặc ulimit(hoặc shopt). Và vì bạn có thể đặt một lệnh phức tạp tùy ý sau -c- cho đến mức độ phức tạp của tập lệnh shell đầy đủ - bạn có thể có cơ hội sử dụng bất kỳ tiết mục nào của nội dung; ví dụ source, read, export, times, setunsetvv

+1 ngoại trừ tôi nghĩ bạn đi quá xa trên các nội trang. Để được rõ ràng echo printf type pwdlà nội dung; vì vậy những set shopt shift read readarray mapfile trap declare/typeset export local let readonly unsetthứ này không ảnh hưởng đến cha mẹ nhưng vẫn có thể hữu ích trong một phức tạp vừa phải -c.
dave_thndry_085

Quan điểm của bạn là gì? Bạn đã đọc viên đạn thứ 6 của tôi, nơi tôi đã nói rằng các nội trang có ích khi kết hợp với (các) lệnh bên ngoài? Bạn đang nói rằng tôi nên đưa ra nhiều ví dụ trong viên đạn số 6?
G-Man nói 'Phục hồi Monica'

Cảm ơn. Có người nói rằng câu trả lời của bạn cũng trả lời một câu hỏi khác , nhưng điều đó có đúng không?
Tim

@Tim: Câu hỏi gì? Tôi thấy năm dấu hỏi trong câu hỏi đó. OK, tôi đang đùa - một chút . Bạn vẫn không chắc chắn về điều gì? Tôi đã cho thấy một ví dụ về sh -cviệc được sử dụng với một dòng lệnh phức tạp bao gồm ba chương trình, một đường ống, một &&và một chuyển hướng; Tôi đã cho thấy một ví dụ về nó đang được sử dụng với một dòng lệnh hỗn hợp bao gồm a cd, a ;và chương trình; Tôi đã cho thấy một ví dụ về nó đang được sử dụng với exec; và tôi đã nói nó có thể được sử dụng với builtins thích echo, kill, printf, pwdtype(và cũng có thể exit, ulimitumask). Bạn muốn biết thêm gì nữa? Tiết (Cont'd)
G-Man nói 'Tái lập lại' '

(Tiếp theo) Nếu bạn có nghĩa là Có nghĩa là execve()có thể hoạt động trên một tập lệnh không?,, (1) không liên quan gì bash -c, và (2) bạn đã thực hiện nghiên cứu gì? Các execvetrang người đàn ông trả lời này, và tìm kiếm của trang web này mang lại này , này , này , này , này , và này .
G-Man nói 'Phục hồi Monica'

5

Chạy bash -c "my command here"so với chỉ chạy my command herechủ yếu khác nhau ở chỗ cái trước bắt đầu một lớp con và cái sau chạy các lệnh trong shell hiện tại.

Theo như các lệnh tích hợp so với các lệnh bên ngoài, nó không thực sự liên quan đến bất cứ thứ gì bạn có thể chạy trong shell hiện tại, bạn có thể chạy trong một lớp con.

Tuy nhiên, có một số khác biệt về hiệu ứng:

  • Các thay đổi đối với môi trường được thực hiện trong lớp con có thể ảnh hưởng đến lớp vỏ cha (thư mục hiện tại, giá trị của các biến môi trường, định nghĩa hàm, v.v.)
  • Các biến được đặt trong trình vỏ mẹ chưa được xuất sẽ không có sẵn trong lớp con.

Điều này khác xa với một danh sách đầy đủ các khác biệt, nhưng nó chứa điểm chính: bạn đang chạy một quy trình khác với bash -c; nó không giống như quy trình ban đầu của bạn.

Ngoài ra còn có một hit hiệu suất phát sinh bằng cách sinh ra một subshell; điều này có liên quan nhất nếu tập lệnh của bạn được chạy thường xuyên hoặc nếu lệnh của bạn nằm trong một vòng lặp nào đó.


1
FYI, tôi trích dẫn câu trả lời của bạn trong câu trả lời của tôi. Tôi đã cố gắng ping bạn từ đó, biết rằng điều đó không làm việc.
G-Man nói 'Phục hồi Monica'

2

Tùy chọn -c về cơ bản chạy một tập lệnh shell nhỏ được cung cấp dưới dạng đối số CLI chứ không phải là tệp.

$ bash -c the_script the_scriptname 1 2 3 

hầu như tương đương với:

$ echo the_script > the_scriptname
$ bash the_scriptname 1 2 3
$ rm the_scriptname

Như bạn có thể thấy từ:

$ bash -c 'printf " ->%s\n" $0 "$@"; echo $-;' scriptname 1 2 3
   ->scriptname
   ->1
   ->2
   ->3
  hBc

(Bằng tiếng Anh: $ 0 == scriptname; $ @ == (1 2 3); và bash sẽ: h lệnh tro; thực hiện mở rộng cuộc đua B và nó đã được chạy với -ccờ)

và:

 $ echo 'printf " ->%s\n" $0 "$@"; echo $-;' > scriptname
 $ bash scriptname 1 2 3 
 ->scriptname
 ->1
 ->2
 ->3
 hB

-1

-chuỗi C

Nếu tùy chọn -c có mặt, thì các lệnh được đọc từ chuỗi. Nếu có các đối số sau chuỗi, chúng được gán cho các tham số vị trí, bắt đầu bằng $ 0.

Điều này sẽ giải quyết câu hỏi của bạn, tôi đoán


cảm ơn. bạn có thể giải thích rõ ràng cho câu hỏi của tôi?
Tim
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.