Jak mogę przypisać wynik polecenia do zmiennej powłoki?


76

Chcę przypisać wynik wyrażenia do zmiennej i połączyć go ciągiem znaków, a następnie wywołać echo. Oto co mam:

#!/bin/bash
cd ~/Desktop;
thefile= ls -t -U | grep -m 1 "Screen Shot";
echo "Most recent screenshot is: "$thefile;

Ale to daje:

Screen Shot 2011-07-03 at 1.55.43 PM.png
Most recent screenshot is: 

Wygląda na to, że nie jest to przypisywane $thefilei jest drukowane w trakcie wykonywania.


Odpowiedzi:


108

Przypisanie powłoki jest pojedynczym słowem, bez spacji po znaku równości. Więc to, co napisałeś, przypisuje pustą wartość thefile; ponadto, ponieważ przypisanie jest zgrupowane z poleceniem, powoduje to, że thefilezmienna środowiskowa jest zmienna, a przypisanie jest lokalne dla tego konkretnego polecenia, tj. tylko wywołanie, aby zobaczyć lsprzypisaną wartość.

Chcesz uchwycić dane wyjściowe polecenia, więc musisz użyć podstawienia polecenia :

thefile=$(ls -t -U | grep -m 1 "Screen Shot")

(Część literatury pokazuje alternatywną składnię thefile=`ls …`; składnia tylnego cytatu jest równoważna składni nawiasów dolara, z wyjątkiem tego, że czasami cytowanie w cudzysłowach jest dziwne, więc po prostu użyj $(…)).

Inne uwagi na temat skryptu:

  • Łączenie -t(sortuj według czasu) z -U(nie sortuj) nie ma sensu; po prostu użyj -t.
  • Zamiast grepdopasowywać zrzuty ekranu, łatwiej jest przekazać symbol wieloznaczny lsi użyć headdo przechwycenia pierwszego pliku:

    thefile=$(ls -t *"Screen Shot"* | head -n 1)
  • Zasadniczo analizowanie danych wyjściowychls jest złym pomysłem . Może to zawieść dość źle, jeśli masz nazwy plików ze znakami niedrukowalnymi. Sortowanie plików według daty jest jednak trudne bez ls, więc jest to akceptowalne rozwiązanie, jeśli wiesz, że w nazwach plików nie będzie znaków, które nie mogą zostać wydrukowane, ani ukośników odwrotnych.

  • Zawsze używaj podwójnych cudzysłowów wokół podstawień zmiennych , tj. Pisz tutaj

    echo "Most recent screenshot is: $thefile"

    Bez podwójnych cudzysłowów wartość zmiennej jest ponownie interpretowana, co spowoduje problemy, jeśli będzie zawierała spacje lub inne znaki specjalne.

  • Nie potrzebujesz średników na końcu linii. Są zbędne, ale nieszkodliwe.
  • W skrypcie powłoki często warto uwzględnić set -e. Mówi to powłoce, aby zakończyła działanie, jeśli jakiekolwiek polecenie zawiedzie (przez zwrócenie niezerowego statusu).

Jeśli masz GNU find (w szczególności jeśli korzystasz z niewbudowanego systemu Linux lub Cygwin), istnieje inne podejście do znajdowania najnowszego pliku: wyświetl findlistę plików i ich daty oraz użyj sorti tailwypakuj najmłodszy plik.

thefile=$(find -maxdepth 1 -type f -name "*Screen Shot*" -printf "%T@ %p" |
          sort -k 1n | tail -n 1)

Jeśli chcesz napisać ten skrypt w zsh zamiast bash, istnieje znacznie łatwiejszy sposób na złapanie najnowszego pliku, ponieważ zsh ma kwalifikatory glob, które pozwalają na dopasowanie symboli wieloznacznych nie tylko nazw, ale także metadanych plików. (om[1])Część po wzór kwalifikatory glob; omsortuje mecze według wieku (tj. według czasu modyfikacji, najnowsze jako pierwsze) i [1]wyodrębnia tylko pierwsze dopasowanie. Całe dopasowanie musi być w nawiasach, ponieważ technicznie jest to tablica, ponieważ globbing zwraca listę plików, nawet jeśli [1]oznacza to, że w tym konkretnym przypadku lista zawiera (najwyżej) jeden plik.

#!/bin/zsh
set -e
cd ~/Desktop
thefile=(*"Screen Shot"*(om[1]))
echo "Most recent screenshot is: $thefile"

7
Łał! Więcej informacji, niż mogłem się spodziewać. Wielokrotnie dziękuję za odpowiedź; Naprawdę doceniam wysiłek włożony w to! Właśnie pokazałeś mi, że naprawdę mam naprawdę wiele do nauczenia się. Idę kupić książkę na bash: P.
Nathan G.,

3
Tak nazwałbym ostateczną odpowiedź! :)
alex

4

Jeśli chcesz to zrobić za pomocą polecenia multiline / multiple / s, możesz to zrobić:

output=$( bash <<EOF
#multiline/multiple command/s
EOF
)

Lub:

output=$(
#multiline/multiple command/s
)

Przykład:

#!/bin/bash
output="$( bash <<EOF
echo first
echo second
echo third
EOF
)"
echo "$output"

Wynik:

first
second
third

To miła odpowiedź. czy istnieje sposób, aby określić zmienną jako część polecenia? na przykładoutput=$(echo $someVariable)
Zach Smith
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.