Łączenie ciągu Bash używane do budowania listy parametrów


12

Biorąc pod uwagę ten bash:

PARMS='-rvu'
PARMS+=" --delete --exclude='.git'"
echo $PARMS
rsync ${PARMS} . ${TARGET}

Echo pokazuje ciąg PARMS zgodnie z oczekiwaniami, nie wyświetla się żaden błąd, ale rsync cicho działa tak, jakby opcje dodane przez + = nie istniały. Działa to jednak zgodnie z oczekiwaniami:

PARMS='-rvu'
rsync ${PARMS} --delete --exclude='.git' . ${TARGET}

Chyba spieprzyłem coś z cytatami bashowymi (zawsze miałem z tym problemy), ale nie jestem pewien, co i dlaczego opcje są ignorowane, nawet jeśli łańcuch wydaje się być poprawnie zbudowany.


1
echo "$PARMS"i rsync "${PARMS}"...
— jasonwryan

Działa to dla mnie w bashwersji 4.2.25 bez żadnych zmian.
— Anthon

Odpowiedzi:


17

Istnieje różnica między:

PARMS+="... --exclude='.git'"

i

... --exclude='.git'

W pierwszym, pojedyncze cytaty są same w sobie, więc dosłownie są obecne w zastąpionym tekście podanym rsyncjako argument. rsyncdostaje argument, którego wartość wynosi --exclude='.git'. W drugim przypadku pojedyncze cudzysłowy są interpretowane przez powłokę w momencie ich pisania, ponieważ same nie są wewnątrz cudzysłowów i rsyncmożna je zobaczyć --exclude=.git.

W tym przypadku nie potrzebujesz w ogóle pojedynczych cudzysłowów - .gitto samo w sobie poprawne słowo powłoki, bez znaków specjalnych, więc możesz używać go dosłownie w poleceniu.

Jednak dla tego rodzaju rzeczy lepsza jest tablica :

PARMS=(-rvu)
PARMS+=(--delete --exclude='.git')
rsync "${PARMS[@]}"

Tworzy to twoje polecenie jako osobne słowa, z dowolnym cytatem, który chcesz interpretować w momencie pisania wiersza tablicy. "${PARMS[@]}"rozwija się do każdego wpisu w tablicy jako osobny argument, nawet jeśli sam argument zawiera w sobie znaki specjalne lub spacje, więc rsyncwidzisz, co napisałeś tak, jak chciałeś.


bashwykonano dzielenie słów po ${PARMS}rozszerzeniu. Więc pojedynczy cytat został również zinterpretowany przez powłokę.
— cuonglm

2
Spróbuj! Zrobiłem. Cytaty pozostają, a jeśli między nimi są spacje, to i tak są to punkty podziału.
— Michael Homer

@Gnouc: Od strony atakujących człowieka: „Cytat: Usuwanie Po poprzednich rozszerzeń, wszystkie nienotowane wystąpień znaków \ , 'i "., Które nie wynikają z jednego z powyższych rozszerzeń są usuwane” „powyżej rozszerzeń” obejmuje rozszerzenie parametrów, które wykonuje rozszerzenie ${PARMS}.
— camh

Dzięki. Rozumiem więc, że w takim przypadku pominięcie pojedynczych cudzysłowów w podwójnych będzie działać, ale ze względu na kompletność - co jeśli będę musiał zacytować jakieś znaki specjalne i nie chciałbym zastosować twojego drugiego podejścia?
— neuviemeporte

Jeśli twoje znaki specjalne nie są częścią IFS(zazwyczaj spacją), nie musisz ich cytować. Jeśli tak, to masz pecha, chyba że zhakujesz coś razem eval- to ogólnie jest trochę mylne, a tablice są właściwym sposobem na poradzenie sobie z tym.
— Michael Homer

2

Oprócz odpowiedzi @Michael Homer , możesz użyć bash funkcji eval :

PARMS='-rvu'
PARMS+=" --delete --exclude='.git'"
echo "$PARMS"
eval "rsync ${PARMS} . "'"${TARGET}"'

2
Możesz, ale nie powinieneś. Tablice zostały dodane specjalnie, aby uniknąć tego użycia eval.
— chepner
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.