bash: Sử dụng một biến để lưu trữ chuyển hướng stderr | stdout


17

Có cách nào để chuyển hướng thiết bị xuất chuẩn và thiết bị xuất chuẩn thông qua biến như thêm tùy chọn lệnh trong tập lệnh không?

Ví dụ tôi có một kịch bản:

#!/bin/bash -x
TEST=">/dev/null 2>&1"
OPT='-p -v'
mkdir $OPT 123/123/123 $TEST

Tôi có thể thấy rằng OPT được thay thế -pmà không có bất kỳ vấn đề nào và bash diễn giải nó dưới dạng tùy chọn. Nhưng chuyển hướng giải thích như tên thư mục.

$ ./test.sh 
+ TEST='>/dev/null 2>&1'
+ OPT='-p -v'
+ mkdir -p -v 123/123/123 '>/dev/null' '2>&1'
mkdir: created directory `123/123'
mkdir: created directory `123/123/123'
mkdir: created directory `>/dev'
mkdir: created directory `>/dev/null'
mkdir: created directory `2>&1'

Có cách nào để nói bash không, rằng $ VAR là chuyển hướng, không phải là tên dirs.

Tái bút Có thể tôi đang đi sai đường, nhưng tôi muốn tạo ra đầu ra dài dòng tùy chọn hoặc không dài dòng từ tập lệnh của mình. Nhưng tôi cần một số đầu ra ngay cả trong chế độ không dài dòng, do đó tôi không thể chuyển hướng toàn bộ thiết bị xuất chuẩn và thiết bị xuất chuẩn, chỉ từ một số lệnh bên trong tập lệnh của tôi.

Câu trả lời:


18

Một giải pháp khác có thể là như sau:

#!/bin/bash

verbose=0

exec 3>&1
exec 4>&2

if ((verbose)); then
  echo "verbose=1"
else
  echo "verbose=0"
  exec 1>/dev/null
  exec 2>/dev/null
fi

echo "this should be seen if verbose"
echo "this should always be seen" 1>&3 2>&4

Sau đó 1>&3 2>&4chỉ thêm vào các lệnh mà bạn muốn xem đầu ra.


Tuyệt quá. Đây chính xác là thứ tôi đã xem. Cảm ơn bạn.
vội vàng

Tôi đã viết một bài viết để giải thích cách thức hoạt động của nó
transang

5

"Làm thế nào" đã được giải thích tốt trong các câu trả lời khác; Tôi muốn giải quyết "tại sao" mã của OP không hoạt động.

Bài phát biểu chính là các chuyển hướng đầu ra được đánh dấu trước khi mở rộng biến. Chuyển hướng thực sự được thực hiện sau khi mở rộng biến (do đó tại sao bạn có thể chuyển hướng đầu ra sang tên tệp được lưu trữ trong một biến), nhưng shell xác định các chuyển hướng để xử lý sau này trước khi các biến được mở rộng.

Nói cách khác, một khi các biến được mở rộng thì "quá muộn" để xem xét một ký tự chuyển hướng ( <hoặc >, v.v.), vì shell đã xác định phần nào của chuỗi lệnh sẽ xử lý như các chuyển hướng.

Để đọc thêm, xem các bước 1 và 3 được liệt kê dưới đây:

LESS='+/^SIMPLE COMMAND EXPANSION' man bash

3

Nó không được hiểu là "tên thư mục", >đang được trích dẫn, vì vậy nó được xử lý theo nghĩa đen (cụ thể hơn là bạn đang gửi chuỗi >dev/null 2>&1. Cách duy nhất của bạn để khắc phục điều này là sử dụng evalhoặc sinh ra một vỏ mới.

Đối với vấn đề "dài dòng" của bạn được đề cập trong câu hỏi của bạn, chỉ cần làm điều này thay vào đó:

verbose=1
if (( verbose )); then
    mkdir -v -p /foo
else
    mkdir -p /foo > /dev/null 2>&1
fi

1

Bạn có rất nhiều khoảng trắng trong các biến của mình, điều này sẽ không được đánh giá đúng. Bạn sẽ muốn sử dụng evalđể thiết lập nó.

#!/bin/bash -x
TEST=">/dev/null 2>&1"
OPT='-p -v'
eval mkdir $OPT 123/123/123 $TEST

Điều này sẽ cho phép $ OPT được chia thành hai đối số ( -p-v) thay vì một ( -p -v) và tương tự với $ TEST. Cũng thay đổi để sử dụng /dev/nullvì rất khó có khả năng bạn sẽ có một devthư mục trong thư mục hiện tại.


0

Câu trả lời của enzotib sử dụng một số phép thuật mô tả tệp tốt, nhưng một giải pháp đơn giản hơn là chỉ sử dụng evaldòng ( tuy nhiên thêm chi phí xử lý), tuy nhiên):

$ rm /tmp/foo
$ ll /tmp/foo
ls: cannot access /tmp/foo: No such file or directory
$ FOO=">/tmp/foo"
$ date $FOO
date: invalid date '>/tmp/foo'
$ cat /tmp/foo
cat: /tmp/foo: No such file or directory
$ eval date $FOO
$ cat /tmp/foo
Thu Dec 13 14:08:17 EST 2018
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.