0 Câu hỏi: Sử dụng lệnh tùy chỉnh trong một chuỗi [trùng lặp]

câu hỏi được tạo ra tại Wed, May 8, 2019 12:00 AM

Tôi gặp phải một vấn đề khi truyền một đối số cho một lệnh trong tập lệnh Bash.

poc.sh:

#!/bin/bash

ARGS='"hi there" test'
./swap ${ARGS}

hoán đổi:

#!/bin/sh
echo "${2}" "${1}"

Đầu ra hiện tại là:

there" "hi

Chỉ thay đổi poc.sh (vì tôi tin rằng hoán đổi thực hiện đúng những gì tôi muốn), làm cách nào để poc.sh vượt qua "hi there" và kiểm tra như hai đối số, với "hi there" không có dấu ngoặc kép xung quanh nó?

    
5
  1. Đây là chủ đề của BashFAQ # 50: mywiki.wooledge.org/BashFAQ/050
    2014-09-26 21: 22: 47Z
3 Câu trả lời                              3                         

Một vài từ giới thiệu

Nếu có thể, không sử dụng các chuỗi được trích dẫn bằng vỏ làm định dạng đầu vào.

  • Thật khó để phân tích một cách nhất quán: Các shell khác nhau có các phần mở rộng khác nhau và các triển khai không shell khác nhau thực hiện các tập hợp con khác nhau (xem deltas trong khoảng từ shlexxargs bên dưới).
  • Thật khó để tạo lập trình. ksh và bash có printf '%q', sẽ tạo ra một chuỗi trích dẫn shell với nội dung của một biến tùy ý, nhưng không tồn tại tương đương với điều này trong tiêu chuẩn sh POSIX.
  • Thật dễ dàng để phân tích xấu . Nhiều người sử dụng định dạng này sử dụng eval, có mối quan tâm bảo mật đáng kể.

Luồng được phân tách bằng NUL là một cách thực hành tốt hơn nhiều, vì chúng có thể biểu diễn chính xác bất kỳ mảng vỏ hoặc danh sách đối số có thể không có sự mơ hồ nào.

xargs, với bashism

Nếu bạn nhận được danh sách đối số của mình từ nguồn đầu vào do con người tạo bằng cách sử dụng trích dẫn shell, bạn có thể cân nhắc sử dụng xargs để phân tích cú pháp. Xem xét:

array=( )
while IFS= read -r -d ''; do
  array+=( "$REPLY" )
done < <(xargs printf '%s\0' <<<"$ARGS")

swap "${array[@]}"

... sẽ đưa nội dung được phân tích của $ARGS vào mảng array. Nếu bạn muốn đọc từ một tệp thay thế, hãy thay thế <filename cho <<<"$ARGS".

xargs, tuân thủ POSIX

Nếu bạn đang cố gắng viết mã tuân thủ POSIX sh, điều này trở nên khó khăn hơn. (Tôi sẽ giả sử đầu vào tệp ở đây để giảm độ phức tạp):

# This does not work with entries containing literal newlines; you need bash for that.
run_with_args() {
  while IFS= read -r entry; do
    set -- "$@" "$entry"
  done
  "$@"
}
xargs printf '%s\n' <argfile | run_with_args ./swap

Các cách tiếp cận này an toàn hơn so với chạy xargs ./swap <argfile vì nó sẽ gây ra lỗi nếu có nhiều hoặc nhiều đối số hơn mức có thể được cung cấp, thay vì chạy các đối số dư thừa dưới dạng các lệnh riêng biệt.

Python shlex - chứ không phải xargs - với bashism

Nếu bạn cần phân tích cú pháp POSIX sh chính xác hơn xargs, hãy xem xét sử dụng mô-đun Python shlex thay thế:

shlex_split() {
  python -c '
import shlex, sys
for item in shlex.split(sys.stdin.read()):
    sys.stdout.write(item + "\0")
'
}
while IFS= read -r -d ''; do
  array+=( "$REPLY" )
done < <(shlex_split <<<"$ARGS")
    
17
2018/03/02 23: 54: 44Z
  1. Điều này dường như không hoạt động với ARGS="\"a\\\"b\" c"? Báo cáo lỗi xargs: trích dẫn kép chưa từng có; theo trích dẫn mặc định là đặc biệt đối với xargs trừ khi bạn sử dụng tùy chọn -0
    2016-12-25 22: 03: 12Z
  2. Điểm công bằng - xargs thực sự không tôn trọng hành vi POSIX sh trong trường hợp đó. Thay vào đó, cập nhật với một thay thế bằng cách sử dụng chức năng shlex.split() của Python 2.
    2016-12-26 18: 51: 12Z
  3. Điều tốt nhất cần làm là đưa OP trở lại đúng hướng: nếu OP cần một thứ như vậy, thì rõ ràng thiết kế của họ đã sai. Trừ khi OP đang viết shell (hoặc cli), trong trường hợp đó, sự lựa chọn ngôn ngữ là sai. Dù bằng cách nào, OP đang làm sai.
    2016-12-26 19: 03: 36Z
  4. @ gniourf_gniourf, ... về lý thuyết, tôi đồng ý. Trong thực tế, mọi người có xu hướng được đưa ra các yêu cầu không có ý nghĩa (hoặc cần tương thích với các hệ thống /thực tiễn lâu đời - có tấn của hệ thống khởi động kế thừaipts cho các ứng dụng Java trôi nổi xung quanh dựa trên danh sách đối số eval được đưa ra ở dạng trích dẫn shell) và có giá trị trong việc có thể giải quyết tình huống xấu tốt nhất ... mặc dù vậy, "không nên làm vậy" một phần của lời khuyên được đưa ra.
    2016-12-26 19: 06: 31Z
  5. @ gniourf_gniourf, ... Tôi đã chỉnh sửa trong phần giới thiệu phù hợp.
    2016-12-26 19: 09: 25Z

Báo giá nhúng không bảo vệ khoảng trắng; họ được đối xử theo nghĩa đen. Sử dụng một mảng trong bash:

args=( "hi there" test)
./swap "${args[@]}"

Trong shell POSIX, bạn bị kẹt khi sử dụng eval (đó là lý do tại sao hầu hết các shell hỗ trợ mảng).

args='"hi there" test'
eval "./swap $args"

Như thường lệ, hãy rất chắc chắn bạn biết nội dung của $args và hiểu cách chuỗi kết quả sẽ được phân tích cú pháp trước khi sử dụng eval.

    
3
2014-09-26 19: 53: 42Z
  1. Tôi có xu hướng tranh luận rằng có nhiều tùy chọn hơn mà eval ở đây. Ngay cả trong POSIX, người ta có thể đọc vào "$@" từ xargs.
    2015-07-17 23: 07: 50Z

Đây có thể không phải là cách tiếp cận mạnh mẽ nhất, nhưng nó đơn giản và dường như hoạt động cho trường hợp của bạn:

## demonstration matching the question
$ ( ARGS='"hi there" test' ; ./swap ${ARGS} )
there" "hi

## simple solution, using 'xargs'
$ ( ARGS='"hi there" test' ; echo ${ARGS} |xargs ./swap )
test hi there
    
0
2017-03-10 23: 15: 47Z
  1. Bình luận: Xử lý chuỗi Bash cực kỳ khó hiểu. xargs xóa bỏ phỏng đoán bằng cách truyền tham số trực tiếp qua exec , bỏ qua thông thường , xử lý chuỗi mà Bash sẽ thực hiện như một phần của xử lý dòng lệnh dựa trên chuỗi.
    2017-04-01 18: 13: 16Z
  2. Tôi không thể chắc chắn về khẳng định của mình về exec. Nhưng tôi đứng trước tuyên bố của mình rằng "Xử lý chuỗi Bash cực kỳ khó hiểu" .
    2017-04-01 18: 23: 43Z
nguồn đặt đây