Znaczenie [„$ {1: 0: 1}” = '-']

18

Mam następujący skrypt do uruchomienia procesu MySQL:

if [ "${1:0:1}" = '-' ]; then
    set -- mysqld_safe "$@"
fi

if [ "$1" = 'mysqld_safe' ]; then
    DATADIR="/var/lib/mysql"
...

Co w tym kontekście oznacza 1: 0: 1?

użytkownik3521621
źródło
1
Naprawdę chciałbym poznać odpowiedź, ale uważam, że jest to trochę zbyt wąskie pytanie dla SF. Głosuję za przeniesieniem go na stronę Unix.
Massimo,

Odpowiedzi:

19

-Najwyraźniej jest to test na argument przerywaną. To naprawdę trochę dziwne. Używa niestandardowego bashrozszerzenia w celu wyodrębnienia pierwszego i tylko pierwszego znaku $1. Jest 0to indeks znaku głowy, a 1długość łańcucha. W [ testpodobny sposób może to być również:

[ " -${1#?}" = " $1" ]

Żadne porównanie nie jest jednak szczególnie przydatne test, ponieważ interpretuje -przerywane argumenty - dlatego używam tam wiodącej przestrzeni.

Najlepszym sposobem na zrobienie tego rodzaju rzeczy - i sposób, w jaki jest to zwykle wykonywane - jest:

case $1 in -*) mysqld_safe "$@"; esac
mikeserv
źródło
1
Blisko; liczba po drugim dwukropku ${1:0:1}to długość, a nie indeks.
chepner,
W pewnym sensie bashowymi z [[: [[ $1 == -* ]].
Arthur2e5,
2
Osobiście nie sądzę, że -będą one stanowić problem test. POSIX podaje definicje znaczeń według liczby argumentów. Ponieważ nie ma takiej opcji, która wymaga dwóch argumentów, powinno być bezpiecznie napisać ją w stanie surowym.
Arthur2e5,
@ Arthur2e5 - masz rację - nie powinny stanowić problemu - i najprawdopodobniej w ogóle nie stanowią problemu. nadal jest to dziwny sposób - po prostu nie pasuje dobrze. Co ma [[ : [[zrobić?
mikeserv
1
@mikeserv Cóż, powinieneś spojrzeć na stronę internetową (jeśli czytasz to z innych źródeł). Mój komentarz brzmiał: „z START_CODE [[END_CODE: START_CODE [[$ 1 == - *]] END_CODE”. Pierwszy [[to tylko nazwa składniowa, a dwukropek to tylko interpunkcja.
Arthur2e5,
11

To zajmie podłańcuch $1od 0 do 1 znaku. Otrzymasz więc pierwszy znak i tylko pierwszy znak ciągu.

Na stronie podręcznika bash3.2:

  ${parameter:offset}
  ${parameter:offset:length}
          Substring  Expansion.   Expands  to  up to length characters of
          parameter starting at the character specified  by  offset.   If
          length is omitted, expands to the substring of parameter start-
          ing at the character specified by offset.   length  and  offset
          are  arithmetic  expressions (see ARITHMETIC EVALUATION below).
          length must evaluate to a number greater than or equal to zero.
          If  offset  evaluates  to a number less than zero, the value is
          used as an offset from the end of the value of  parameter.   If
          parameter  is  @,  the  result  is length positional parameters
          beginning at offset.  If parameter is an array name indexed  by
          @ or *, the result is the length members of the array beginning
          with ${parameter[offset]}.  A negative offset is taken relative
          to  one  greater than the maximum index of the specified array.
          Note that a negative offset must be separated from the colon by
          at  least  one space to avoid being confused with the :- expan-
          sion.  Substring indexing is zero-based unless  the  positional
          parameters are used, in which case the indexing starts at 1.
pisklęta
źródło
6

Testuje, że pierwszym znakiem pierwszego argumentu $1jest myślnik -.

1: 0: 1 są wartości parametrów ekspansji: ${parameter:offset:length}.

To znaczy:

  • Nazwa: nazwany parametr 1, tj .:$1
  • Rozpocznij: od pierwszego znaku 0(ponumerowanego od 0).
  • Długość: za 1 znak.

W skrócie: pierwszy znak pierwszego parametru pozycyjnego $1.
To rozszerzenie parametru jest dostępne w ksh, bash, zsh (przynajmniej).


Jeśli chcesz zmienić linię testową:

[ "${1:0:1}" = "-" ]

Opcje Bash

Inne bezpieczniejsze rozwiązania bash mogą być:

[[ $1 =~ ^- ]]
[[ $1 == -* ]]

Bezpieczniej, ponieważ nie ma to problemów z cytowaniem (wewnątrz nie jest wykonywany podział [[)

POSIXly opcje.

W przypadku starszych, mniej zdolnych pocisków można zmienić na:

[ "$(echo $1 | cut -c 1)" = "-" ]
[ "${1%%"${1#?}"}"        = "-" ]
case $1 in  -*) set -- mysqld_safe "$@";; esac

Tylko polecenie case jest bardziej odporne na błędne cytowanie.


źródło