2014-04-26 14 views
11

Próbuję napisać skrypt, który przyjmie jako dodatkowe argumenty w wierszu poleceń pusty ciąg z podwójnymi cudzysłowami. Chcę, aby skrypt przekazywał te argumenty wraz z podwójnym cudzysłowem pustym łańcuchem, jeśli jest on podany, ale zamiast tego interpreter poleceń wydaje się interpretować taki argument jako pusty ciąg i usuwa cytaty. Czy jest jakiś sposób to zrobić?Jak przekazać pusty ciąg z podwójnymi cudzysłowami do skryptu bash?

Jako prosty przykład chciałbym mieć w script.sh Plik:

#!/bin/bash 
/home/myapp $1 $2 

Jeśli uruchomić w wierszu:

$ ./script.sh arg1 "" 

Skrypt po prostu wykonuje "/home/myapp arg1", ale tęskni/ignoruje drugi argument: (""). Chcę, żeby zachować ten pusty łańcuch, a zamiast tego wykonać: /home/myapp arg1 ""

Odpowiedz

3

Można wykryć ile parametry pozycyjne były przekazywane do skryptu przez examining the $# parameter. Na przykład, jeśli jest to 2 lub więcej, to wiesz, że coś zostało przekazane dla $2, nawet jeśli $2 jest puste (cytaty usunięte przez wywołanie powłoki).Poniższa realizuje tę logikę i przekazuje "" do wywoływanego programu (w tym przypadku echo) jeżeli parametr został przekazany ale pusty:

#!/bin/bash 

if [ $# -ge 2 ]; then 
    if [ "$2" ]; then 
     arg2="$2" 
    else 
     arg2='""' 
    fi 
    echo "$1 $arg2" 
elif [ $# == 1 ]; then 
    echo "$1" 
fi 

wyjściowa:

 
$ ./args.sh a 
a 
$ ./args.sh a "" 
a "" 
$ ./args.sh a 1 
a 1 
$ 
+0

Doskonały, dokładnie to, czego potrzebowałem Dzięki! – Josh

+1

Ustawienie 'arg2 = '" "'' będzie wyglądało dobrze, gdy będziesz echo, ale jeśli spróbujesz użyć go do przekazania pustego ciągu do czegoś innego (jak w '/ home/myapp $ 1 $ arg2'), wygrywa ' t działa - przejdzie ciąg znaków składający się z dwóch podwójnych cudzysłowów, a nie z pustego ciągu znaków. –

+0

@GordonDavisson * Chcę, aby zachował ten pusty ciąg i zamiast tego wykonaj: '/ home/myapp arg1" "* * Czy nie jest to dokładnie to, o co prosi OP? –

2

Będziecie go uniknąć stosując odwrotny ukośnik

$ ./script.sh arg1 \"\" 

można badać np na echo:

$ echo \"\" 
"" 
+0

Dzięki, tak zgadzam to działa, czy jest jakiś sposób, aby nie wymagać od użytkownika, aby uciec cytaty za pomocą jakiegoś skryptu magii, aby wykryć, że weszli taki pusty ciąg i zastąpić polecenie z podwójnymi cytatami? – Josh

+0

@ Nie jestem świadomy takiej magii. To parsowanie jest wykonywane przez powłokę, więc musisz zmodyfikować powłokę, aby zastosować różne reguły analizy składni. –

2

Ucieknij za pomocą odwrotnych ukośników lub umieść je w pojedynczych cudzysłowach.

2

Można również umieścić je w pojedynczym cudzysłowie, aby uzyskać ich wartości literalne, np. :

]$ echo '""' 
    "" 

Na przykład, w skrypcie:

]# cat a.bash 
    #!/bin/bash   
    echo a$1b 

    ]$ ./a.sh '""' 
    a""b 

    ]$ ./a.sh "" 
    ab 
3

celu uzupełnienia Kaz's helpful explanation:
Jeśli wprost "[email protected]" rajd pustych argumenty zostaną przepuszczone, zbyt:

#!/bin/bash 

/home/myapp "[email protected]" 

Przejście przez gh "[email protected]" zachowuje oryginalne argumenty dokładnie jak przekazane w - nawet argumentów przekazanych jako pustych strunach (minęły jak np '' lub "" lub "$someVar", gdzie zmienna someVar jest ustawiona lub zawiera pusty ciąg znaków).


W przypadku nie może być więcej niż 2 argumenty:

#!/bin/bash 

# Copy the (up to) first 2 arguments - whether they're empty strings or not - 
# to a separate array. 
firstTwo=("${@:1:2}") 
shift; shift # Remove the first 2 arguments from the arguments array. 

# Invoke the app with the (up to) first 2 arguments stored in the new array. 
/home/myapp "${firstTwo[@]}" 

# Process the remaining arguments, if any. 
for a; do 
    echo "remaining: [$a]" 
done 
10

Jesteś prawidłowo przechodzącą pusty ciąg argument do skryptu.

Jest to skrypt, który jest brudząc go:

#!/bin/bash 
/home/myapp $1 $2 

Skrypt nie chroni ekspansję $1 i $2 z word-rozszczepienia. Oznacza to, że jeśli $1 i $2 zawierają wiele słów, zmieniają się w pojedyncze argumenty, a jeśli którekolwiek z nich rozszerza się do zera, po prostu znikają.

Powinno być:

#!/bin/bash 
/home/myapp "$1" "$2" 

Ogólnie można zrobić skrypt przekazać wszystkie swoje argumenty do wywoływanego programu, podobnie jak to:

/home/myapp "[email protected]" 

Te cytaty to tylko skorupa składni; nie są częścią samych danych argumentów. Po wpisaniu w powłoce program "", na poziomie systemu operacyjnego program otrzymuje pusty ciąg znaków języka C: wskaźnik do bajtu o wartości null. Brak ofert.

Możesz przekazać argument "" (dwuliterowy ciąg złożony z dwóch podwójnych cudzysłowów), ale to nie jest pusty argument. Jednym ze sposobów na to jest na przykład '""': zawijanie go w pojedyncze cudzysłowy.

Jedynym powodem takiego działania jest manipulowanie składnią powłoki na poziomie meta: przekazywanie fragmentów kodu powłoki kodu źródłowego, takich jak cytowane żetony, puste lub inne. Powłoka ma polecenie o nazwie eval, które przyjmuje kod źródłowy jako argument (lub wiele argumentów) i ocenia je.

przed wywołaniem eval, linia poleceń podlega rozszerzeniu. Ta ekspansja usuwa składnię $empty_shell_string_sytnax i zastępuje ją zawartością, znakami "". Tak więc eval dostaje ciąg empty_var="". Ocenia to i tak empty_var jest ustawiony na pusty łańcuch, jak wskazuje składnia.

+0

Masz rację co do potrzeby podwójnego cytowania odwołań do argumentów, ale jeśli bezwarunkowo zacytujesz '$ 2' (' "$ 2" '), to zostanie _podejściem przekazane jako (pusty) argument, nawet gdy NIE podano drugiego argumentu przekazane, co nie jest zamierzeniem PO; '" $ @ "', przeciwnie, działa zgodnie z przeznaczeniem; +1 dla pozostałej części wyjaśnienia. – mklement0

+1

Możesz obejść problem @ mklement0 wzmianek, używając np. '/ home/myapp $ {1 +" $ 1 "} $ {2 +" 2 $ "}". To jest trochę okrężne, ale działa tak, jak to jest, że '$ {var + coś}' konstruuje się do 'czegoś' JEŚLI zdefiniowano' $ var' - więc jeśli '$ 2' jest niezdefiniowane,' $ {2 + "$ 2 "}' rozszerza się do zera i znika; jeśli zdefiniowane jest '$ 2' (nawet jeśli jest zdefiniowane jako pusty ciąg), rozwija się do' "$ 2" ', a podwójne cudzysłowy chronią go przed dzieleniem słów i znikają - jeśli puste. –

0

Spróbuj tego:

cmd=yourcomand; 
n=0; for a in "[email protected]"; do n=$((n +1)); cmd="$cmd \${$n+\"\$$n\"}"; done 
eval $cmd 
+1

Chociaż ten kod może odpowiedzieć na pytanie, podanie dodatkowego kontekstu dotyczącego tego, w jaki sposób i/lub dlaczego rozwiązuje problem, poprawiłoby długoterminową wartość odpowiedzi. –

+0

Jest to oparte na notatce Kaz i Gordona Davissona powyżej, dziękuję. Zauważ jednak, że ogólnie rozszerzenie $ {X + "$ X"} może przynieść niepożądane wyniki w zależności od tego, jakie znaki zawiera wartowierna wartość. Najlepiej więc użyć ogólnego zastępowania wszystkich zmiennych w wierszu poleceń, tylko po sprawdzeniu, czy obecny jest pusty ciąg znaków. Z powyższych odpowiedzi nie widzę jeszcze ogólnego rozwiązania. – alphasoup

Powiązane problemy