Próbując dowiedzieć się, jak przekonwertować argument na liczbę całkowitą w celu wykonania arytmetyki, a następnie wydrukować go, powiedz dla addOne.sh:
Próbuję sformatować twoje pytanie, ale pozostaje niejasne. printf "1 + %s\n" $1 won't do ?
Archemar
Odpowiedzi:
87
W bash nie wykonuje się „konwersji argumentu na liczbę całkowitą w celu wykonania arytmetyki”. W bash zmienne są traktowane jako liczba całkowita lub ciąg znaków w zależności od kontekstu.
Aby wykonać arytmetykę, należy wywołać arytmetyczny operator rozszerzenia $((...)). Na przykład:
$ a=2
$ echo "$a + 1"2+1
$ echo "$(($a + 1))"3
lub ogólnie preferowane:
$ echo "$((a + 1))"3
Należy pamiętać, że bash (w przeciwieństwie do ksh93, zsh lub yash) wykonuje tylko arytmetykę liczb całkowitych . Jeśli masz liczby zmiennoprzecinkowe (liczby dziesiętne), możesz skorzystać z innych narzędzi. Na przykład użyj bc:
Używanie $ (()) lub (()) jest niebezpieczne, jeśli nie wiesz, jakie są ciągi znaków (np. Dane wejściowe użytkownika). Rozważ to: foo = foo ((foo + = 0)) Spowoduje to awarię skryptu podczas próby rekurencyjnej oceny foo. To samo z: foo = foo foo = $ ((foo + 0))
W bashmożna wykonać konwersję z dowolnej wartości na liczbę całkowitą za pomocą printf -v :
printf -v int '%d\n'"$1"2>/dev/null
Liczba zmiennoprzecinkowa zostanie przekonwertowana na liczbę całkowitą, a nic nie będzie wyglądać tak, jakby liczba została przekonwertowana na 0. Potęgowanie zostanie obcięte do liczby przed e
Przykład:
$ printf -v int '%d\n'123.1232>/dev/null
$ printf '%d\n'"$int"123
$ printf -v int '%d\n' abc 2>/dev/null
$ printf '%d\n'"$int"0
$ printf -v int '%d\n'1e102>/dev/null
$ printf '%d\n'"$int"1
W innych pociskach bez printf -vtego można osiągnąć dzięki zastępowaniu poleceń:int="$(printf '%d' 123.123 2>/dev/null)"
Adrian Günter,
2
To nie działa w bash.
Michael Martinez
@MichaelMartinez jesteś pewien? Jakiej bashużywasz wersji ?
cuonglm
GNU bash, wersja 4.2.46 (1) -release (x86_64-redhat-linux-gnu)
Michael Martinez
5
Podobna sytuacja pojawiła się ostatnio podczas opracowywania skryptów bash do uruchamiania zarówno w środowiskach Linux, jak i OSX. Wynik jednej komendy w OSX zwrócił ciąg zawierający kod wyniku; tj " 0". Oczywiście nie udało się poprawnie przetestować w następującym przypadku:
if[[ $targetCnt !=0]];then...
Rozwiązaniem było wymuszenie (tj. „Konwersja”) wyniku na liczbę całkowitą, podobną do odpowiedzi @ John1024 powyżej, aby działał zgodnie z oczekiwaniami:
==itp. w [[(również [aka test) zrobić porównanie ciągów. Istnieją różne operatory dla porównania arytmetyczne, np [[ $targetcnt -ne 0 ]]; zobacz manpage (lub info) w wyrażeniach warunkowych. Aby przyciąć spacje konkretnie, możesz użyć niewymienionego [rozszerzenia zmiennej, [ $targetcnt == 0 ]aby uzyskać domyślne dzielenie słów (NIE zrobione w [[), ale ogólnie takie podejście prowadzi do niebezpieczeństwa.
dave_thompson_085
-2
dbają o kody kolorów, nawet w trace ( -x) nie będą się pojawiać, co by je rozdawało, to że ciąg, który ma być liczbą, jest zawijany w cudzysłów, bez względu na to, jak go wydrukujesz.
Głosowałem w dół, ponieważ odpowiedź jest nieco niejasna. Być może mógłbyś dodać do czego skrypt powinien zostać poprawiony?
Time4Tea,
to była najwyższa odpowiedź w poszukiwaniu bash + liczba całkowita + ciąg, więc dodałem związaną z tym informację, która nie została uwzględniona w odpowiedziach, to znaczy, gdy łańcuchy są owinięte kolorowymi kodami, może nie być jasne, dlaczego operacje takie jak $((var+var))nawet nie powiodły się choć jeśli ty echolub printfobaj jesteście tymi samymi. Nie znam tej poprawki, ponieważ mogłem ją naprawić, wyłączając kody kolorów u źródła danych wyjściowych. Aby wykryć to w dziennikach śledzenia, zobaczysz przypisaną zmienną var='0', która powinna być po prostu taka, jaka powinna byćvar=0
przed
Co możesz zrobić, to upewnić się, że dane wyjściowe nie mają kodów kolorów, sedjeśli nie możesz go wyłączyć
printf "1 + %s\n" $1 won't do ?
Odpowiedzi:
W bash nie wykonuje się „konwersji argumentu na liczbę całkowitą w celu wykonania arytmetyki”. W bash zmienne są traktowane jako liczba całkowita lub ciąg znaków w zależności od kontekstu.
Aby wykonać arytmetykę, należy wywołać arytmetyczny operator rozszerzenia
$((...))
. Na przykład:lub ogólnie preferowane:
Należy pamiętać, że bash (w przeciwieństwie do ksh93, zsh lub yash) wykonuje tylko arytmetykę liczb całkowitych . Jeśli masz liczby zmiennoprzecinkowe (liczby dziesiętne), możesz skorzystać z innych narzędzi. Na przykład użyj
bc
:Lub możesz użyć powłoki z obsługą arytmetyki zmiennoprzecinkowej zamiast bash:
źródło
W inny sposób możesz użyć
expr
Dawny:
źródło
W
bash
można wykonać konwersję z dowolnej wartości na liczbę całkowitą za pomocą printf -v :Liczba zmiennoprzecinkowa zostanie przekonwertowana na liczbę całkowitą, a nic nie będzie wyglądać tak, jakby liczba została przekonwertowana na 0. Potęgowanie zostanie obcięte do liczby przed
e
Przykład:
źródło
printf -v
tego można osiągnąć dzięki zastępowaniu poleceń:int="$(printf '%d' 123.123 2>/dev/null)"
bash
używasz wersji ?Podobna sytuacja pojawiła się ostatnio podczas opracowywania skryptów bash do uruchamiania zarówno w środowiskach Linux, jak i OSX. Wynik jednej komendy w OSX zwrócił ciąg zawierający kod wyniku; tj
" 0"
. Oczywiście nie udało się poprawnie przetestować w następującym przypadku:Rozwiązaniem było wymuszenie (tj. „Konwersja”) wyniku na liczbę całkowitą, podobną do odpowiedzi @ John1024 powyżej, aby działał zgodnie z oczekiwaniami:
źródło
==
itp. w[[
(również[
akatest
) zrobić porównanie ciągów. Istnieją różne operatory dla porównania arytmetyczne, np[[ $targetcnt -ne 0 ]]
; zobacz manpage (lub info) w wyrażeniach warunkowych. Aby przyciąć spacje konkretnie, możesz użyć niewymienionego[
rozszerzenia zmiennej,[ $targetcnt == 0 ]
aby uzyskać domyślne dzielenie słów (NIE zrobione w[[
), ale ogólnie takie podejście prowadzi do niebezpieczeństwa.dbają o kody kolorów, nawet w trace (
-x
) nie będą się pojawiać, co by je rozdawało, to że ciąg, który ma być liczbą, jest zawijany w cudzysłów, bez względu na to, jak go wydrukujesz.źródło
$((var+var))
nawet nie powiodły się choć jeśli tyecho
lubprintf
obaj jesteście tymi samymi. Nie znam tej poprawki, ponieważ mogłem ją naprawić, wyłączając kody kolorów u źródła danych wyjściowych. Aby wykryć to w dziennikach śledzenia, zobaczysz przypisaną zmiennąvar='0'
, która powinna być po prostu taka, jaka powinna byćvar=0
sed
jeśli nie możesz go wyłączyć