Dodaj argumenty do 'bash -c'


22

Powiedzmy, że chcę uruchomić polecenie przez Bash w następujący sposób:

/bin/bash -c "ls -l"

Według strony podręcznika Bash, mógłbym również uruchomić go w następujący sposób:

#               don't process arguments after this one
#               |   pass all unprocessed arguments to command
#               |   |
#               V   V
/bin/bash -c ls -- -l

z wyjątkiem tego, że nie działa (wydaje się ignorowane). Czy robię coś źle, czy źle interpretuję stronę podręcznika?

Odpowiednie cytaty od człowieka:

Jeśli dostępna jest opcja -c, polecenia są odczytywane z łańcucha. Jeśli po ciągu znajdują się argumenty, są one przypisywane do parametrów pozycyjnych, zaczynając od 0 $.

i

A - sygnalizuje koniec opcji i wyłącza dalsze przetwarzanie opcji. Wszelkie argumenty po - są traktowane jak nazwy plików i argumenty.

Odpowiedzi:


33

Źle interpretujesz stronę podręcznika. Po pierwsze, część dotycząca --sygnalizowania końca opcji nie ma znaczenia dla tego, co próbujesz zrobić. Do -cnadpisania reszty wiersza poleceń od tego momentu, tak, że nie dzieje się przez obsługi opcji atakujących na wszystkich, co oznacza, że --zostanie przeniesione na polecenia, nie obsługiwane przez bash jako koniec opcji znacznik.

Drugi błąd polega na tym, że dodatkowe argumenty są przypisywane jako parametry pozycyjne do uruchomionego procesu powłoki, a nie przekazywane jako argumenty do polecenia. Więc to, co próbujesz zrobić, może być wykonane jako:

/bin/bash -c 'echo "$0" "$1"' foo bar
/bin/bash -c 'echo "$@"' bash foo bar

W pierwszym przypadku przekazanie echa parametrów $0i $1jawnie, aw drugim przypadku użycie "$@"do rozwinięcia tak normalnie jak „wszystkie parametry pozycyjne z wyjątkiem 0 $”. Zauważ, że w takim przypadku musimy również przekazać coś do wykorzystania $0; Wybrałem „bash”, ponieważ $0normalnie tak właśnie byłoby, ale wszystko inne działałoby.

Jeśli chodzi o przyczyny to zrobić w ten sposób, zamiast po prostu przechodząc żadnych argumentów oddawać bezpośrednio do komendy Państwo listę: uwaga, że dokumentacja mówi „polecenie s odczytywane są z łańcucha”, w liczbie mnogiej. Innymi słowy, ten schemat pozwala na:

/bin/bash -c 'mkdir "$1"; cd "$1"; touch "$2"' bash dir file

Pamiętaj jednak, że lepszym sposobem na osiągnięcie pierwotnego celu może być użycie envzamiast bash:

/usr/bin/env -- "ls" "-l"

Jeśli nie potrzebujesz żadnej funkcji udostępnianej przez powłokę, nie ma powodu, aby z niej korzystać - użycie envw tym przypadku będzie szybsze, prostsze i mniej pisania. I nie musisz myśleć tak ciężko, aby upewnić się, że bezpiecznie poradzi sobie z nazwami plików zawierającymi metaznaki powłoki lub białe znaki.


3

Nie jestem pewien, jaki jest twój cel, ale jeśli po prostu próbujesz zbudować maszynę Rube Goldberg - „urządzenie, wynalazek, urządzenie lub aparatura, która jest celowo przeprojektowana lub przesadzona, aby wykonać bardzo proste zadanie w bardzo skomplikowana moda ”- następnie spróbuj

sh -c 'ls $0' -l

lub

sh -c 'ls $1' supercalifragilisticexpialidocious -l

lub nawet

sh -c 'ls -$0' l

Powinieneś być w stanie zrozumieć, jak działają one z odpowiedzi godlygeek.

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.