Tại sao có EOF ở giữa các đối số?


20

Tôi muốn viết một hàm bash nhỏ để tôi có thể nói bash, import oshoặc from sys import stdoutnó sẽ sinh ra một trình thông dịch Python mới với mô-đun được nhập.

Hàm sau fromtrông như thế này:

from () {
    echo "from $@" | xxd
    python3 -i -c "from $@"
}

Nếu tôi gọi đây là:

$ from sys import stdout
00000000: 6672 6f6d 2073 7973 2069 6d70 6f72 7420  from sys import 
00000010: 7374 646f 7574 0a                        stdout.
  File "<string>", line 1
    from sys
           ^
SyntaxError: invalid syntax
>>> 

Các byte trong from sys

66 72 6f 6d 20 73 79 73 20
f  r  o  m     s  y  s    

Không có EOF trong đó, nhưng trình thông dịch Python đang hành xử như thể nó đọc EOF. Có một dòng mới ở cuối luồng, đó là dự kiến.

fromChị gái, nhập khẩu toàn bộ mô-đun Python, trông giống như thế này và giải quyết vấn đề bằng cách vệ sinh và xử lý chuỗi và không thành công trên các mô-đun không tồn tại.

import () {
  ARGS=$@
  ARGS=$(python3 -c "import re;print(', '.join(re.findall(r'([\w]+)[\s|,]*', '$ARGS')))")
  echo -ne '\0x04' | python3 -i
  python3 -c "import $ARGS" &> /dev/null
  if [ $? != 0 ]; then
    echo "sorry, junk module in list"
  else
    echo "imported $ARGS"
    python3 -i -c "import $ARGS"
  fi
}

Điều đó giải quyết vấn đề về EOF không giải thích được trong luồng, nhưng tôi muốn hiểu tại sao Python nghĩ rằng có EOF.

Câu trả lời:


42

Bảng trong câu trả lời Stack Overflow này (lấy từ Bash Hackers Wiki ) giải thích cách các biến Bash khác nhau được mở rộng:

Bạn đang làm python -i -c "from $@", điều đó biến thành python -i -c "from sys" "import" "stdout"-cchỉ nhận một đối số duy nhất, vì vậy nó đang chạy lệnh from sys. Bạn muốn sử dụng $*, nó sẽ mở rộng thành python -i -c "from sys import stdout"(giả sử $IFSlà không đặt hoặc bắt đầu bằng khoảng trắng).


2
Cảm ơn bạn đã hoàn tác, vì đây là thông tin có giá trị :)
mèo

1
Tôi nghĩ rằng đây nên là câu trả lời được chấp nhận vì điều này thực sự giải quyết được vấn đề, người khác nêu lên chỉ giải thích vấn đề, nhưng nó không đưa ra giải pháp hoặc cách giải quyết khác
Ferrybig

Câu trả lời tốt. Bảng đó thực sự đến từ Bash Hackers Wiki. Bạn có thể thêm phân bổ thích hợp và xác minh rằng bạn có quyền phân phối không?
Cuộc đua nhẹ nhàng với Monica

22

strace, như mọi khi, sẽ hiển thị những gì đang diễn ra:

bash-4.1$ echo $$
3458

Và, ở nơi khác (hoặc bạn có thể tìm ra cách strace bash ...gọi hàm):

bash-4.1$ strace -ff -o blah -p 3458

Và trở lại trong vỏ đầu tiên đó:

bash-4.1$ from sys import stdout
  File "<string>", line 1
    from sys
           ^
SyntaxError: invalid syntax
>>> 
bash-4.1$ 

Và sau đó trở lại trong stracevỏ:

Process 3458 attached
Process 25224 attached
^CProcess 3458 detached
bash-4.1$ grep exec blah.*
blah.25224:execve("/usr/bin/python", ["python", "-i", "-c", "from sys", "import", "stdout"], [/* 54 vars */]) = 0

Do đó, -cđối số thực tế là -c "from sys"do cách "$@"mở rộng hoặc lệnh cắt ngắn mà pythonbarfs trên.


9

$@trong dấu ngoặc kép mở rộng đến một danh sách các yếu tố, "$1" "$2" "$3"vv

#!/bin/bash
expand () {
    for string in "from $@" ; do
        echo "$string"
    done
}

expand sys import stdout

Python hy vọng mã sẽ nằm trong một đối số, không phải là một chuỗi các đối số.


6

Python đang được gọi là

execve("/usr/bin/python", ["python", "-i", "-c", "from sys", "import", "stdout"], [/* 54 vars */])

(xem câu trả lời của thrig ).

Để được $@mở rộng dưới dạng một chuỗi (giả sử là lành mạnh $IFS), bạn có thể sử dụng $*bên trong dấu ngoặc kép:

python3 -i -c "from $*"

Xác nhận với strace -e execve:

execve("/usr/bin/python", ["python", "-i", "-c", "from sys import stdout"], [/* 54 vars */]) = 0

2

Strace làm gì cho thấy các đối số được sử dụng là gì. Nhưng phương pháp đơn giản nhất để xem những gì đang được xử lý là thêm một printf '<%s> 'dòng trước mỗi dòng có liên quan và đóng echo(để tạo dưới dạng dòng mới):

Vì vậy, chức năng có thể được thay đổi thành này:

from () {
    printf '<%s> ' "from $@"; echo
    printf '<%s> ' python3 -i -c "from $@"; echo
}

Và khi được gọi:

$ from sys import stdout
<from sys> <import> <stdout> 
<python3> <-i> <-c> <from sys> <import> <stdout>

Rõ ràng là "từ sys" đang được gửi đến python như là một đối số.
Đó là những gì python nhận được, và python hành động "từ sys".

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.