GNU znajduje i maskuje {} dla niektórych powłok - które?

34

Strona man dla GNU find stwierdza:

-exec command ;
    [...] The  string `{}'  is  replaced  by the current 
    file name being processed everywhere it occurs in the 
    arguments to the command, not just in arguments where 
    it is alone, as in some  versions  of  find.
    Both  of  these  constructions might need to be escaped 
    (with a `\') or quoted to protect them from expansion 
    by the shell. 

To od człowieka do find(GNU findutils) 4.4.2.

Teraz przetestowałem to za pomocą bash i dash i oba nie muszą {}być maskowane. Oto prosty test:

find /etc -name "hosts" -exec md5sum {} \; 

Czy istnieje skorupa, dla której naprawdę muszę zamaskować aparat ortodontyczny? Zauważ, że nie zależy to od tego, czy znaleziony plik zawiera puste (wywołane z bash):

find ~ -maxdepth 1 -type d -name "U*" -exec ls -d {} \; 
/home/stefan/Ubuntu One

Zmienia się, jeśli znaleziony plik zostanie przekazany do podpowłoki:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d {}' \; 
ls: cannot access /home/stefan/Ubuntu: No such file or directory
ls: cannot access One: No such file or directory

które można rozwiązać przez:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "$0"' {} \;

W odróżnieniu:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "{}"' \; 
/home/stefan/Ubuntu One

ale nie o tym mówi strona podręcznika, prawda? Która skorupa traktuje {}w inny sposób?

nieznany użytkownik
źródło
@Volker Siegel: Twoja edycja mogła się odbyć w dobrej intencji, ale sprawdziłem moją aktualną instrukcję obsługi i twoje poprawki są błędne, przegapiłeś także okazję podsumowania swoich zmian, co jest złym nawykiem, więc wycofuję twoje zmiany. Przepraszam kolego.
użytkownik nieznany
Och, dziękuję za wycofanie go, jeśli coś zepsuło. Pamiętałem, że kompilator tekstowy, który generuje format strony podręcznika używany do generowania tych „cytatów typograficznych” jako artefakt definicji renderowania. Może również renderować do TeXa w celu idealnego formatowania wydruku. Zauważyłem cytaty, ponieważ pomieszały podświetlanie składni. Założyłem, że ten niezwykły pierwszy cytat jest błędny, gdy jest używany w kodzie, i nadal to zakładam. Zauważ, że dwie zmiany dotyczyły tekstu opisu, a nie kodu. Jeśli więc postrzegamy je jako typografię - rendering estetyczny - mają rację.
Volker Siegel,
Wygląda na to, że w renderowaniu informacji wyjściowych ten sam cytat jest używany po obu stronach. Nie ma wątpliwości, że moja zmiana różni się od oryginału, masz rację. Ale czy to spowodowało jakiś problem? (Pierwszy cytat uważam za błąd w definicji renderowania człowieka, to o ile wiem jedyny przypadek typografii.)
Volker Siegel,
Właśnie sprawdziłem: `{} 'nie działa w wierszu poleceń. To technicznie poprawne, ale nie podoba mi się, że niczego niepodejrzewający użytkownik dostaje dziwny błąd, gdy próbuje go skopiować i wkleić.
Volker Siegel,
@VolkerSiegel: To tekst prozy, a nie kod, więc co użytkownik powinien skopiować i wkleić tutaj? Jest to cytat ze strony podręcznika użytkownika z 2011 roku. Nie widzę żadnej wartości korygującej fragment, aby następnie wskazać, dlaczego wprowadziłem poprawki na stronie podręcznika. Temat jest wystarczająco skomplikowany. Gdyby to było twoje pytanie, nie próbowałbym cię przekonać, aby dokładnie cytować stronę podręcznika, ale na moje pytanie nie mam nastroju na kompromisy. Cytowanie to cytowanie.
użytkownik nieznany

Odpowiedzi:

26

Podsumowanie : Jeśli kiedykolwiek istniała powłoka, która się rozszerzyła {}, to teraz są to naprawdę stare, starsze rzeczy.

W powłoce Bourne'a i w powłokach zgodnych z POSIX nawiasy klamrowe ( {i }) są zwykłymi znakami (w przeciwieństwie (do, )które są separatorami słów, takimi jak ;i &, [i ]które są znakami globowania). Wszystkie poniższe ciągi znaków powinny być drukowane dosłownie:

$ echo { } {} {foo,bar} {1..3}
{ } {} {foo,bar} {1..3}

Słowo składające się z jednego nawiasu klamrowego jest słowem zastrzeżonym , które jest wyjątkowe tylko wtedy, gdy jest pierwszym słowem polecenia.

Ksh implementuje rozszerzenie nawiasów jako niekompatybilne rozszerzenie powłoki Bourne'a. Można to wyłączyć za pomocą set +B. Bash pod tym względem emuluje ksh. Zsh implementuje również rozszerzenie nawiasu klamrowego; tam można go wyłączyć za pomocą set +Ilub setopt ignore_braceslub emulate sh. Żadna z tych powłok nie rozszerza się {}w żadnym wypadku, nawet jeśli jest to podciąg słowa (np. foo{}bar), Ze względu na powszechne użycie w argumentach do findi xargs.

Single Unix v2 zauważa, że

W niektórych systemach historycznych nawiasy klamrowe są traktowane jako operatory sterowania. Aby pomóc w przyszłych działaniach normalizacyjnych, aplikacje przenośne powinny unikać używania niecytowanych nawiasów klamrowych do reprezentowania samych znaków. Możliwe jest, że przyszła wersja normy ISO / IEC 9945-2: 1993 może tego wymagać {i }być traktowana indywidualnie jako operatorzy sterowania, chociaż token {}będzie prawdopodobnie wyjątkiem od tego szczególnego przypadku ze względu na często używany find {}konstrukt.

Uwaga ta została upuszczona w kolejnych wersjach standardu; te przykładyfind mają nienotowanych zastosowań {}, podobnie jak przykłady dlaxargs . Tam mogły {}być cytowane historyczne muszle Bourne'a , ale do tej pory byłyby to naprawdę stare systemy starszego typu.

Implementacje csh, które mam pod ręką (OpenBSD 4.7, BSD csh na Debianie , tcsh) rozwijają {foo}się, fooale pozostawiają w {}spokoju.

Gilles „SO- przestań być zły”
źródło
1
@geekosaur: Tylko niewielki podzbiór markdown działa w komentarzach . Nie wiem co próbujesz powiedzieć. Jeśli chodzi o rozszerzenie nawiasu klamrowego przez ksh i wsp., Przeczytaj mój akapit rozpoczynający się od „Ksh implementuje nawias klamrowy jako niekompatybilne rozszerzenie”.
Gilles 'SO - przestań być zły'
2
To było bash(patrz $BASH_VERSION). Ekspansja nawiasów klamrowych jest bardzo żywa i dobrze.
geekozaur
2
O to właśnie chodziło . {}Składnia pochodzi csh, ale {}rozszerzony na pusty ciąg. Nowsze powłoki rozpoznają, że to nonsens, ale wciąż istnieją pewne stare csh.
geekozaur
1
@geekosaur: Czy możesz powiedzieć, która konkretna wersja csh na której platformie? Wolałbym przetestować to sam (jeśli jest to możliwe na Linuksie) lub mieć pewność, że osoba przetestuje to sam.
użytkownik nieznany
1
@geekosaur, {}foorozwinąłby się do foo, ale {}rozwinąłby się do {}(z wyjątkiem sytuacji, gdy znajduje się w backticks, ale cytowanie nie pomogło) i został udokumentowany jako taki. Sprawdziłem to pod kątem csh 2BSD (pierwsze wydanie), 2.79BSD, 2.8BSD i 2.11BSD.
Stéphane Chazelas,
12

{}Musiały być cytowany w wersji fishskorupy przed 3.0.0.

$ fish -c 'echo find -exec {} \;'
find -exec  ;

I w powłoce rc (również akangaopartej na rc, ale nie es):

$ rc -c "echo find -exec {} ';'"
line 1: syntax error near '{'

Prawdopodobnie nie są to powłoki, które autorzy dokumentacji GNU mieli na myśli, pisząc ten tekst, odkąd fishzostał wydany po raz pierwszy w 2005 r. (Podczas gdy ten tekst lub podobny był już w 1994 r.) I rcnie był pierwotnie powłoką uniksową.

Istnieją pogłoski o niektórych wersjach csh(powłoki, która wprowadziła rozszerzenie nawiasów klamrowych) wymagających tego. Trudno jednak przypisać je tym, ponieważ pierwsza wersja csh2BSD tego nie zrobiła. Tutaj, jak przetestowano w emulatorze PDP11:

# echo find -exec {} \;
find -exec {} ;

A strona podręcznika 2BSD cshwyraźnie stwierdza :

W specjalnym przypadku `{',`}' i `{} 'są przekazywane bez zakłóceń.

Byłbym więc bardzo dziwny, gdyby później złamała go kolejna wersja csh lub tcsh.

Mogło być obejście niektórych błędów w niektórych wersjach. Nadal z tym cBS 2BSD (to samo w 2.79BSD, 2.8BSD, 2.11BSD):

# csh -x
# echo foo {} bar
echo foo {} bar
foo {} bar
# echo `echo foo {} bar`
echo `echo foo {} bar`
echo foo {} bar
foo  bar

Cytowanie nie pomaga jednak:

# echo `echo foo '{}' bar`
echo `echo foo '{}' bar`
echo foo {} bar
foo  bar

Możesz podać całe zastąpienie polecenia:

# echo "`echo foo {} bar`"
echo `echo foo {} bar`
echo foo {} bar
foo {} bar

Ale to przekazuje jeden argument do tego zewnętrznego echa.

W cshlub tcsh, musisz podać cytat, {}gdy nie jest on sam, jak w:

find . -name '*.txt' -type f -exec cp {} '{}.back' \;

(chociaż tego rodzaju findużycie nie jest przenośne, ponieważ niektóre findrozszerzają się tylko {}wtedy, gdy są same).

Stéphane Chazelas
źródło
1

Jednym słowem csh. basha inne współczesne powłoki rozpoznają, że użytkownik prawdopodobnie nie prosi o rozszerzenie null nawiasu klamrowego. (Modern cshjest w rzeczywistości tcshi może również {}rozsądnie obsługiwać .)

geekozaur
źródło
Miło to słyszeć, ale proszę o coś przeciwnego: skorupa, dla której nie radzi sobie z tym rozsądnie.
użytkownik nieznany
Zakładasz, że ktoś wejdzie i rozerwie odniesienie strony informacyjnej do dodatkowych cytatów tylko dlatego, że wszystkie systemy Linux mają nowsze csh. Nie wszyscy używają narzędzi GNU w systemie Linux; w rzeczywistości dość często instaluje się je na starszych komercyjnych systemach uniksowych, których pakiety poleceń są ograniczone. (Wymiana cshna tych systemach jest mniej prawdopodobna, ponieważ skrypty systemowe mogą polegać na osobliwościach oryginału csh, a nawet gdyby wszyscy użytkownicy byli skonfigurowani do korzystania z nowszej wersji csh, rootprawie na pewno musiałaby pozostać w pakiecie).
geekozaur
2
Nie. Prowadzę debatę z facetem, który mówi, że na naszej wiki powinniśmy zawsze doradzać, aby używać {{}, ponieważ strona podręcznika tak mówi. A teraz chciałbym wiedzieć, czy jest jakaś powłoka, której nie używam, jak ksh, zsh, tcsh, csh lub XYZsh, której nie wiem, dla których to twierdzenie jest prawdziwe, lub czy szczerze mogę założyć, że nie ma. Jeśli istnieją powłoki dla różnych Uniksów, które potrzebują „{}”, byłoby to dobre wytłumaczenie, dlaczego zdanie wciąż znajduje się na stronie podręcznika, ale nie jest odpowiednie jako porada dla początkujących w Linuksie.
użytkownik nieznany
Teraz zastanawiam się, czy pdkshrobi to dobrze ... chociaż prawidłowa odpowiedź na to pytanie brzmi prawdopodobnie „ kshFOSS”.
geekozaur
4
Pdksh, podobnie jak mksh, ksh93, bash i zsh, rozwija nawiasy klamrowe tylko wtedy, gdy pomiędzy nimi występuje przecinek (lub ..dla ksh93, bash i zsh). Tylko (t) csh rozwija {foo}się foo, a nawet pozostawia w {}spokoju (przynajmniej na ostatnich BSD).
Gilles 'SO - przestań być zły'