2012-07-26 40 views
5

Tôi muốn chạy tập lệnh bash sau, được lưu trữ trong một chuỗi Elisp, không phải trong tệp .sh, sau đó lưu trữ kết quả vỏ trong một biến.Chạy tập lệnh bash nhiều chuỗi từ Emacs

#!/bin/bash 
IFS=: read -ra _dirs_in_path <<< "$PATH" 

for _dir in "${_dirs_in_path[@]}"; do 
    for _file in "${_dir}"/*; do 
     [[ -x ${_file} && -f ${_file} ]] && printf '%s\n' "${_file##*/}" 
    done 
done 

Tôi không thể chạy shell-command trên tập lệnh bash, bao gồm nhiều chuỗi. Emacs and Long Shell Commands cũng không giúp ích gì cho tôi, vì compilecomint-run cũng yêu cầu các lệnh, không phải cú pháp bash.

Làm cách nào để chạy tập lệnh bash phức tạp từ Elisp?

+0

nếu Mx vùng vỏ lệnh-on-thất bại , vui lòng gửi báo cáo lỗi –

Trả lời

6

lệnh Multiline cũng tốt để cung cấp như một tham số để bash -c nếu bạn trích dẫn chúng như bạn sẽ bất kỳ tranh cãi vỏ khác có thể chứa metacharacters vỏ, ví dụ:

(setq my-command 
     (concat "IFS=: read -ra dirs <<<\"$PATH\"\n" 
       "for dir in ${dirs[@]}; do\n" 
       " echo got dir \"$dir\"\n" 
       "done\n")) 

(shell-command (format "bash -c %s" (shell-quote-argument my-command))) 
2

Điều này có lẽ sẽ làm những gì bạn muốn. Thêm bổ nếm thử :)

(defun example-multiline-shell-command() 
    (interactive) 
    (with-temp-buffer 
    (insert "#!/bin/bash 
IFS=: read -ra _dirs_in_path <<< \"$PATH\" 

for _dir in \"${_dirs_in_path[@]}\"; do 
    for _file in \"${_dir}\"/*; do 
     [[ -x ${_file} && -f ${_file} ]] && printf '%s\n' \"${_file##*/}\" 
    done 
done") 
    (write-region (point-min) (point-max) "~/temp.sh") 
    (shell-command "source ~/temp.sh" (current-buffer)) 
    (buffer-string))) 

EDIT Oh, và FYI "${_dirs_in_path[@]}" sẽ kết thúc xấu nếu các tập tin có các khoảng trống hoặc các ký tự khác có thể được coi là dải phân cách trong tên.

+0

Không, cú pháp '" $ {arrayvar [@]} "' hoàn toàn an toàn bất kể sự hiện diện của các siêu ký tự shell trong bất kỳ phần tử nào của 'arrayvar'. – Sean

0

shell-command thực sự hoạt động trên cú pháp bash nhiều chuỗi. Vấn đề của tôi là shell-command không biết biến môi trường bash, bao gồm PATH. Những gì tôi đã làm: thay thế tất cả " bằng \" trong tập lệnh và đặt nó vào một chuỗi dễ đọc, sau đó gán một số thư mục cho PATH. Đây là mã, thành công xuất ra tất cả các tệp thi hành trong hệ thống đến bộ đệm *Shell Command Output*.

(let ((path "PATH='/usr/local/bin:/usr/bin:/bin'") 
     (command "IFS=: read -ra _dirs_in_path <<< \"$PATH\" 

for _dir in \"${_dirs_in_path[@]}\"; do 
    for _file in \"${_dir}\"/*; do 
     [[ -x ${_file} && -f ${_file} ]] && printf '%s\n' \"${_file##*/}\" 
    done 
done")) 
    (shell-command (concat path ";" command))) 

Tôi vẫn quan tâm đến cách tạo compile cũng hoạt động với tập lệnh bash nhiều chuỗi.

Lưu ý về PATH: Tôi không sử dụng (getenv "PATH") trong dung dịch trên là vì, theo như tôi hiểu, các nhà quản lý X hiển thị (bao gồm xdm, gdm và kdm) do not run shell before Xsession, vì vậy một emacs chạy từ GUI sẽ có khác nhau biến môi trường từ các biến bash. Tôi chạy emacs --daemon khi khởi động qua cron, đường dẫn của tôi được thiết lập trong /etc/profile~/.profile, vì vậy Emacs không nhận được PATH từ đó.

Steve Purcell đề xuất một số code (xem thêm biến thể onetwo của nó trên SO) để đảm bảo Emacs có cùng biến môi trường, bao gồm PATH, làm vỏ.

Các vấn đề liên quan