bash: stderr | stdout yönlendirmesini saklamak için bir değişken kullanın


17

Komut dosyasına komut seçenekleri eklemek gibi değişken aracılığıyla stdout ve stderr'i yönlendirmenin herhangi bir yolu var mı?

Örneğin bir senaryom var:

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

OPT'nin -pherhangi bir sorun olmadan değiştirildiğini görebiliyorum ve bash bunu seçenek olarak yorumluyor. Ancak yeniden yönlendirme dizin adı olarak yorumlanır.

$ ./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'

Bash demenin herhangi bir yolu var mı, $ VAR dirs isimleri değil, yönlendirme.

PS. Yanlış yolda olabilirim, ama senaryomdan isteğe bağlı ayrıntılı veya ayrıntılı olmayan çıktı yapmak istiyorum. Ancak ayrıntılı olmayan modda bile bazı çıktılara ihtiyacım var, bu yüzden sadece stdout ve stderr'i sadece komut dosyamdaki bazı komutlardan yönlendiremiyorum.

Yanıtlar:


18

Başka bir çözüm aşağıdaki olabilir:

#!/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

Ardından 1>&3 2>&4yalnızca çıktısını görmek istediğiniz komutlara ekleyin .


Harika. Bu tam olarak izlediğim şey. Teşekkür ederim.
acele

Bunun nasıl çalıştığını açıklamak için bir makale yazdım
transang

5

Diğer cevaplarda "nasıl" iyi açıklanmıştır; Ben OP neden kodu çalışmıyor "neden" adreslemek istiyorum.

Kilit not, çıktı yönlendirmelerinin değişken genişletmeden önce işaretlenmiş olmasıdır . Yönlendirmeler aslında değişken genişletmeden sonra gerçekleştirilir (bu nedenle çıktıyı neden bir değişkente saklanan bir dosya adına yönlendirebilirsiniz), ancak kabuk , değişkenler genişletilmeden önce sonraki işlemler için yeniden yönlendirmeleri tanımlar .

Başka bir deyişle, değişkenler genişletildikten sonra, yönlendirme karakterinin ( <veya >vb.) Dikkate alınması "geç" olur , çünkü kabuk, komut dizesinin hangi bölümlerini yeniden yönlendirme olarak işleyeceğini zaten belirlemiştir.

Daha fazla okuma için, aşağıdaki 1. ve 3. adımlara bakın:

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

3

Bu bir "dizin adı" olarak yorumlayarak değil >, daha spesifik olarak, sen dize gönderiyor (kelimenin tam anlamıyla tedavi altına nedenle, alıntı yapılan >dev/null 2>&1. Dolaşmakta bu kullanıyorsa Sizin tek yolu evalveya yeni bir kabuk ekranına geçerken.

Sorunuzda belirttiğiniz "ayrıntılı" sorununuza gelince, bunun yerine şunu yapın:

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

1

Değişkenlerinizde doğru değerlendirilmeyecek çok fazla alan var. Bunu evalayarlamak için kullanmak isteyeceksiniz .

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

Bu, $ OPT öğesinin $ TEST ile bir ( ) yerine aynı ( -pve -v) yerine iki bağımsız değişkene bölünmesini sağlar -p -v. Ayrıca , geçerli dizinde /dev/nullbir devdizininizin olması pek olası olmadığından kullanmak için değiştirildi .


0

enzotib'in cevabı bazı iyi dosya tanımlayıcı sihir kullanır, ancak daha basit bir çözüm sadece evalsatırı kullanmak olacaktır (ancak bu işlem ek yükü ekler):

$ 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.