Mam polecenie zapisane w zmiennej. Udawajmy, że zmienna $i
ma wartość:
cat -nT index.php |grep 'someregex'
Gdy próbuję wykonać powyższą zmienną przez wpisanie, $i
nie powiedzie się, ponieważ powłoka próbuje wykonać całą zmienną jako jedno polecenie. Próbowałem także użyć eval($i)
i wprowadzić $i
backticks.
Jak mogę wykonać powłokę $i
tak, jakby była poleceniem? I dlaczego to nie działa tak samo jak.
$i='echo hi'; $i
Czy to dlatego, że musiałem włamać się w pojedyncze cytaty? (Ponieważ nie możesz ich zagnieździć.) Obecnie moim rozwiązaniem jest
echo $i > /foo; . /foo
Ale nie chcę tworzyć pliku tylko do tego, aby go usunąć później.
Mam na myśli „włamałem się do pojedynczych cytatów:
$i='cat index.php | grep -P '"'"'MYREGEXHERE'"'"
Odpowiedzi:
Krótka odpowiedź: patrz BashAQ # 50: Próbuję umieścić polecenie w zmiennej, ale złożone przypadki zawsze zawodzą! .
Długa odpowiedź: wynika to z kolejności, w jakiej bash analizuje wiersz poleceń. W szczególności szuka rzeczy takich jak potoki i przekierowania, zanim rozszerzy wartości zmiennych, i nie wraca i nie szuka ponownie potoków itp. W wartościach rozszerzonych. Zasadniczo zmienne są podstawiane mniej więcej w połowie procesu analizowania, więc wartość jest dopiero w połowie analizowana przed wykonaniem.
Aby rozwiązać ten problem, musisz odpowiedzieć na pytanie @ slhck: dlaczego polecenie jest przechowywane w zmiennej w pierwszej kolejności? Jaki jest faktyczny problem, który próbujesz rozwiązać? W zależności od rzeczywistego celu istnieje wiele możliwych rozwiązań:
Nie przechowuj go w zmiennej, po prostu uruchom go bezpośrednio. Przechowywanie poleceń do późniejszego wykorzystania jest trudne, a jeśli tak naprawdę nie potrzebujesz, po prostu nie.
Użyj funkcji zamiast zmiennej. W końcu po to są:
Główną wadą tego jest to, że nie można dynamicznie utworzyć funkcji - nie można warunkowo dołączyć lub wykluczyć kodu z funkcji (chociaż sama funkcja może mieć elementy warunkowe, które są wybierane podczas jej wykonywania).
Zastosowanie
eval
. Należy to uznać za ostateczność, ponieważ łatwo jest uzyskać nieoczekiwane zachowanie. Zasadniczo uruchamia polecenie przez kolejne pełne parsowanie, więc wszystkie potoki itp. Mają pełne znaczenie - ale oznacza to również, że części polecenia, które uważałeś za dane, również zostaną przeanalizowane i być może wykonane. Nazwy plików zawierające metaznaki powłoki (potok, średnik, cytat / apostrof itp.) Mogą mieć dziwne, a czasem niebezpieczne efekty. Jeśli użyjeszeval
, przynajmniej podwój cudzysłów, w przeciwnym razie jego zawartość zostanie zasadniczo przeanalizowana półtora razy, z jeszcze dziwniejszym rezultatem.EDYCJA: Innym standardowym podejściem „zapisz polecenie w zmiennej” jest użycie tablicy zamiast prostej zmiennej. Umożliwia to przechowywanie polecenia ze złożonymi argumentami (np. Zawierającymi spacje) bez problemów, ale nie przechowuje rzeczy takich jak potoki i przekierowania. Zatem podejście tablicowe nie będzie przydatne w tym konkretnym przypadku.
źródło
eval
metodę. To powstrzymało mnie od zadawania tego samego pytania :). Mam coś takiego,sudo rsync -aAHXi -n --delete-excluded --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/lost+found","/mnt/DATA/*","/var/log/*","/var/swap","/var/cache/apt/archives/*.deb"} -e ssh root@piac_wireless:/ /home/mrx/Docs/RPi/backup/piac/piac_usb-root
że niepoprawne wykonanie wykluczeń.eval
do tego - istnieje zbyt wiele sposobów, aby się nie udać. Lepszym sposobem na to jest tablica. Zobacz tutaj , tutaj i tutaj dla przykładów.To powinno po prostu działać:
Uwaga, która
eval
wprowadza potencjalne luki w zabezpieczeniach i nieoczekiwane sytuacje, dlatego należy z niej korzystać, o ile w ogóle, ze szczególną ostrożnością.źródło
eval
, naprawdę musisz użyć podwójnego cudzysłowu (eval "$i"
), aby uniknąć wyjątkowo dziwnych efektów. Na przykład wypróbuj to za pomocąa="cat -nT index.php |grep ' .* '"
(tzn. Wyrażenie regularne powinno pasować do dwóch spacji z dowolną sekwencją znaków między nimi) i zobaczyć, co się właściwie dzieje. Aby uzyskać dodatkowy kredyt, wyjaśnij, dlaczego tak się dzieje.Podczas deklarowania zmiennej nie należy używać znaku dolara jako prefiksu.
Spróbuj tego:
źródło