2010-06-23 5 views
16
function foo() { 
[email protected] 
echo $A 
} 

foo bla "hello ppl" 

Chcę wyjście będzie:
„bla” „Hello ppl”Bash: Łączy wszystkie argumenty i owinąć je cudzysłowy

Co muszę zrobić zamiast elipsy?

+0

Co próbujesz osiągnąć?Czy dane wyjściowe 'foo' mogą być użyte jako dane wejściowe do niczego lub czy chcesz tylko tekst nieprzetworzony? – msw

+0

To powinno być użyte jako dane wejściowe dla innego polecenia (w tym przypadku poczta). – rui

+4

@rubim: wtedy myślę, że robisz to znacznie trudniej, niż to konieczne. 'mail" $ @ "' dałoby wyniki bez kroku parsowania/ponownej analizy. Jeśli '" $ @ "' nie jest we właściwym stanie, pokaż, co masz. – msw

Odpowiedz

3

Można użyć „$ @” traktować każdy parametr jako dobrze, oddzielny parametru, a następnie w pętli nad każdym parametrem:

function foo() { 
for i in "[email protected]" 
do 
    echo -n \"$i\"" " 
done 
echo 
} 

foo bla "hello ppl" 
+1

+1 To rozwiązanie działa! Jestem leniwy, więc zwykle upuszczam część "w" $ @ "i używam tylko" na " –

+0

. Zapomniałem o tym wspomnieć w pytaniu, ale zamierzałem to zrobić bez użycia pętli. Szukałem jakiejś magicznej ekspansji bashów. – rui

3

ninjalj miał prawo pomysł, ale korzystanie z cytatów było dziwne częściowo dlatego, że to, o co prosi OP, nie jest najlepszym formatem wyjściowym dla wielu zadań powłoki. Właściwie nie mogę dowiedzieć się, co ma za zadanie, ale:

function quote_args { 
    for i ; do 
     echo \""$i"\" 
    done 
} 

stawia swoje argumenty za cytowany jedną linię, która jest zwykle najlepszym sposobem, aby karmić innych programów. Dostaniesz wyjście w formie, że nie poprosi o:

$ quote_args this is\ a "test really" 
"this" 
"is a" 
"test really" 

ale można ją łatwo przekształcić i to jest idiom, że większość wolałaby powłoki inwokacje:

$ echo `quote_args this is\ a "test really"` 
"this" "is a" "test really" 

ale chyba że jest przechodząc kolejną przepustkę eval, dodatkowe cytaty prawdopodobnie zepsują rzeczy. Oznacza to, że ls "is a file" pokaże plik is a file podczas

$ ls `quote_args is\ a\ file` 

spróbuje listy "is, a i file" który prawdopodobnie nie ma.

2

Nie pętla wymagane:

foo() { local saveIFS=$IFS; local IFS='"'; local a="${*/#/ \"}"; echo "$a"\"; IFS=$saveIFS; } 

Zapisywanie IFS nie jest konieczne w tym prostym przykładzie, zwłaszcza przywrócenie go tuż przed zakończeniem czynności, ze względu na fakt, że local jest używany. Jednak uwzględniłem to na wypadek, gdyby inne rzeczy wchodziły w funkcję, która może wpłynąć na zmienioną wersję.

Przykład uruchomić:

$ foo a bcd "efg hij" k "lll mmm nnn " ooo " ppp qqq " rrr\ sss 
"a" "bcd" "efg hij" "k" "lll mmm nnn " "ooo" " ppp qqq " "rrr sss" 
6

pomocą parametru podstawienie dodać "na początku i sufiks:

function foo() { 
    A=("${@/#/\"}") 
    A=("${A[@]/%/\"}") 
    echo -e "${A[@]}" 
} 

foo bla "hello ppl" kkk 'ss ss' 

wyjściowy

"bla" "hello ppl" "kkk" "ss ss" 
21

@msw ma rację (w górę komentarze na pytanie).Jednak inny pomysł, aby wydrukować argumenty z cytatami: używać niejawny iteracji printf:

foo() { printf '"%s" ' "[email protected]"; echo ""; } 

foo bla "hello ppl" 
# => "bla" "hello ppl" 
+3

Ding! Wygrywasz dużą nagrodę. Gigantyczny pluszowy miś lub cztero-stopowy bank na monety? –

+0

Dlaczego dodałeś echo ""; na końcu? Czy to nie jest konieczne. – EminezArtus

+0

Tak więc wyjście zakończyłoby się znakiem nowej linii. Po prostu wygląda ładnie i nie zepsuje podpowiedzi. Rozumiem, że jest to niepotrzebne, gdy zostanie wywołane z poleceniem podstawienia –

1

Jedynym rozwiązaniem w tym momencie, że szanuje backslashy i cytaty wewnątrz argumentu:

$ concatenate() { printf "%q"" " "[email protected]"; echo ""; } 
$ concatenate arg1 "arg2" "weird arg3\\\\\\bbut\" legal!" 
arg1 arg2 weird\ arg3\\\\\\bbut\"\ legal\! 

Zawiadomienie " % q "" "

% q argument jest drukowany w formacie, który może być ponownie wykorzystany jako ona ll wprowadzanie, unikanie znaków niedrukowalnych za pomocą proponowanej składni POSIX $ 1 'za pomocą .

znaki specjalne (\, \b Backspace ...) rzeczywiście będzie interpretowany przez program odbiorczym, nawet jeśli nie są wyświetlane interpretowane wyjścia terminala. Test

Miejmy:

# display.sh: Basic script to display the first 3 arguments passed 
echo -e '#!/bin/bash'"\n"'echo -e "\$1=""$1"; echo -e "\$2=""$2"; echo -e "\$3=""$3"; sleep 2;' > display.sh 
sudo chmod 755 display.sh 

# Function to concatenate arguments as $ARGS 
# and "evalutate" the command display.sh $ARGS 
test_bash() { ARGS=$(concatenate "[email protected]"); bash -c "./display.sh ""$ARGS"; } 

# Test: Output is identical whatever the special characters 
./display.sh arg1 arg2 arg3 
test_bash arg1 arg2 arg3 

Więcej testy komplikować:

./display.sh arg1 "arg2-1:Y\b-2:Y\\b-3:Y\\\b-4:Y\\\\b-5:Y\\\\\b-6:Y\\\\\\b" "arg3-XY\bZ-\"-1:\-2:\\-3:\\\-4:\\\\-5:\\\\\-6:\\\\\\-" 
test_bash arg1 "arg2-1:Y\b-2:Y\\b-3:Y\\\b-4:Y\\\\b-5:Y\\\\\b-6:Y\\\\\\b" "arg3-XY\bZ-\"-1:\-2:\\-3:\\\-4:\\\\-5:\\\\\-6:\\\\\\-" 

W display.sh używamy echo -e zamiast tylko echo lub printf w celu interpretowania znaków specjalnych. Jest to tylko reprezentatywne, jeśli Twój program je interpretuje.

-e umożliwiają interpretację backslashem uchodzi

Jeśli -e obowiązuje następujące sekwencje rozpoznawane:

  • \ ukośnikowe
  • \ alert (B)
  • \ b backspace
  • Itp.

NB: \b jest znakiem backspace, więc kasuje Y w przykładzie.

Zauważ, że ten przykład nie ma być powielana w prawdziwym kodzie:

Dzięki przyjętej odpowiedzi i Danny Hong answer w "Jak uniknąć podwójnego cudzysłowu wewnątrz podwójnego cudzysłowu?"