Konsekwentnie widzę odpowiedzi cytujące ten link stwierdzające definitywnie: „Nie analizuj ls
!” Niepokoi mnie to z kilku powodów:
Wygląda na to, że informacje w tym linku zostały zaakceptowane hurtowo, bez drobnych pytań, chociaż potrafię wybrać przynajmniej kilka błędów w swobodnym czytaniu.
Wydaje się również, że problemy wskazane w tym łączu nie wywołały chęci znalezienia rozwiązania.
Z pierwszego akapitu:
... kiedy pytasz
[ls]
o listę plików, pojawia się ogromny problem: Unix dopuszcza prawie dowolny znak w nazwie pliku, w tym białe znaki, znaki nowej linii, przecinki, symbole potoku i prawie wszystko, czego kiedykolwiek chciałbyś użyć jako ogranicznik oprócz NUL. ...ls
oddziela nazwy plików znakami nowej linii. Jest to w porządku, dopóki nie masz pliku z nową linią w nazwie. A ponieważ nie znam żadnej implementacji,ls
która pozwala na zakończenie nazw plików ze znakami NUL zamiast znaków nowej linii, nie możemy bezpiecznie uzyskać listy nazw plikówls
.
Bummer, prawda? Jak zawsze możemy obsługiwać nowa linia zakończona notowanej zestaw danych dla danych, które mogą zawierać znaki nowej linii? Cóż, jeśli ludzie odpowiadający na pytania na tej stronie nie robią tego rodzaju rzeczy na co dzień, myślę, że mieliśmy kłopoty.
Prawda jest jednak taka, że większość ls
implementacji zapewnia bardzo prosty interfejs API do analizowania wyników i wszyscy robiliśmy to od samego początku, nawet nie zdając sobie z tego sprawy. Nie tylko możesz zakończyć nazwę pliku na null, ale możesz także zacząć od null lub dowolnego innego dowolnego ciągu, jaki możesz chcieć. Co więcej, możesz przypisać te dowolne ciągi według typu pliku . Proszę wziąć pod uwagę:
LS_COLORS='lc=\0:rc=:ec=\0\0\0:fi=:di=:' ls -l --color=always | cat -A
total 4$
drwxr-xr-x 1 mikeserv mikeserv 0 Jul 10 01:05 ^@^@^@^@dir^@^@^@/$
-rw-r--r-- 1 mikeserv mikeserv 4 Jul 10 02:18 ^@file1^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul 10 01:08 ^@file2^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul 10 02:27 ^@new$
line$
file^@^@^@$
^@
Zobacz to po więcej.
Teraz jednak kolejna część tego artykułu mnie naprawdę przyciąga:
$ ls -l
total 8
-rw-r----- 1 lhunath lhunath 19 Mar 27 10:47 a
-rw-r----- 1 lhunath lhunath 0 Mar 27 10:47 a?newline
-rw-r----- 1 lhunath lhunath 0 Mar 27 10:47 a space
Problem polega na tym, że z wyjścia
ls
ani użytkownik, ani komputer nie mogą stwierdzić, które części stanowią nazwę pliku. Czy to każde słowo? Nie. Czy to każda linia? Nie. Nie ma poprawnej odpowiedzi na to pytanie poza: nie możesz powiedzieć.Zauważ też, jak
ls
czasami garbles dane pliku (w naszym przypadku okazało się\n
postać w między słowami „a” i „nowej linii” w ? Znakiem zapytania ......
Jeśli chcesz po prostu iterować wszystkie pliki w bieżącym katalogu, użyj
for
pętli i globu:
for f in *; do
[[ -e $f ]] || continue
...
done
Autor nazywa to mylącymi nazwami plików, gdy ls
zwraca listę nazw plików zawierających globusy powłoki, a następnie zaleca użycie globu powłoki do pobrania listy plików!
Rozważ następujące:
printf 'touch ./"%b"\n' "file\nname" "f i l e n a m e" |
. /dev/stdin
ls -1q
f i l e n a m e
file?name
IFS="
" ; printf "'%s'\n" $(ls -1q)
'f i l e n a m e'
'file
name'
POSIX definiuje-1
i -q
ls
Operandy tak:
-q
- Wymusza<tab>
zapisywanie każdego wystąpienia znaków niedrukowalnych nazw plików jako znaków znaku zapytania ('?'
). Implementacje mogą domyślnie zapewniać tę opcję, jeśli dane wyjściowe dotyczą urządzenia końcowego.
-1
- (cyfra jeden.) Wymusza na wyjściu jeden wpis na linię.
Globowanie nie jest pozbawione własnych problemów - ?
dopasowuje dowolny znak, więc wiele pasujących ?
wyników na liście będzie pasowało do tego samego pliku wiele razy. Łatwo sobie z tym poradzić.
Chociaż nie chodzi o to, jak to zrobić - w końcu nie zajmuje wiele i pokazano to poniżej - byłem zainteresowany, dlaczego nie . Uważam, że najlepsza odpowiedź na to pytanie została zaakceptowana. Sugerowałbym, abyś częściej skupiał się na mówieniu ludziom, co mogą zrobić, niż na tym, czego nie mogą. Myślę, że co najmniej mniej prawdopodobne jest udowodnienie, że się mylisz.
Ale po co w ogóle próbować? Wprawdzie moją główną motywacją było to, że inni mówili mi, że nie mogę. Wiem bardzo dobrze, że ls
wyniki są tak regularne i przewidywalne, jak tylko można sobie życzyć, o ile wiesz, czego szukać. Dezinformacja niepokoi mnie bardziej niż większość rzeczy.
Prawda jest jednak taka, że z godnym uwagi wyjątkiem zarówno Patricka, jak i Wumpusa Q. Odpowiedzi Wumbley (pomimo niesamowitego uchwytu tego ostatniego) uważam większość informacji w odpowiedziach tutaj za w większości poprawnych - glob powłoki jest łatwiejszy w użyciu i ogólnie bardziej skuteczne, jeśli chodzi o wyszukiwanie w bieżącym katalogu, niż parsowanie ls
. Nie są one jednak, przynajmniej w moim zakresie, to wystarczający powód, aby uzasadnić szerzenia dezinformacji albo cytowany w artykule powyżej nie są one akceptowalne uzasadnienie „ nie analizować ls
. ”
Należy pamiętać, że niespójne wyniki Patryka odpowiedź brzmi to głównie wynikiem niego używając zsh
potem bash
. zsh
- domyślnie - nie przenosi $(
polecenia podziału tekstu )
na przenośne. Więc kiedy pyta, gdzie poszła reszta plików? odpowiedź na to pytanie jest taka, że zjadła je twoja skorupa. Dlatego musisz ustawić SH_WORD_SPLIT
zmienną podczas używania zsh
i obsługi przenośnego kodu powłoki. Uważam, że jego brak odnotowania tego w odpowiedzi jest strasznie mylący.
Odpowiedź Wumpusa nie jest dla mnie obliczalna - w kontekście listy ?
postać jest globem powłoki. Nie wiem, jak inaczej to powiedzieć.
Aby poradzić sobie z przypadkiem wielu wyników, musisz ograniczyć chciwość globu. Poniższe elementy utworzą bazę testową okropnych nazw plików i wyświetlą ją dla Ciebie:
{ printf %b $(printf \\%04o `seq 0 127`) |
sed "/[^[-b]*/s///g
s/\(.\)\(.\)/touch '?\v\2' '\1\t\2' '\1\n\2'\n/g" |
. /dev/stdin
echo '`ls` ?QUOTED `-m` COMMA,SEP'
ls -qm
echo ; echo 'NOW LITERAL - COMMA,SEP'
ls -m | cat
( set -- * ; printf "\nFILE COUNT: %s\n" $# )
}
WYNIK
`ls` ?QUOTED `-m` COMMA,SEP
??\, ??^, ??`, ??b, [?\, [?\, ]?^, ]?^, _?`, _?`, a?b, a?b
NOW LITERAL - COMMA,SEP
?
\, ?
^, ?
`, ?
b, [ \, [
\, ] ^, ]
^, _ `, _
`, a b, a
b
FILE COUNT: 12
Teraz będę bezpieczny każdy znak, który nie jest /slash
, -dash
, :colon
, lub alfanumeryczny znak w glob powłoki następnie sort -u
liście dla wyjątkowych rezultatów. Jest to bezpieczne, ponieważ ls
ma już za sobą wszelkie znaki, które nie mogą zostać wydrukowane. Zegarek:
for f in $(
ls -1q |
sed 's|[^-:/[:alnum:]]|[!-\\:[:alnum:]]|g' |
sort -u | {
echo 'PRE-GLOB:' >&2
tee /dev/fd/2
printf '\nPOST-GLOB:\n' >&2
}
) ; do
printf "FILE #$((i=i+1)): '%s'\n" "$f"
done
WYNIK:
PRE-GLOB:
[!-\:[:alnum:]][!-\:[:alnum:]][!-\:[:alnum:]]
[!-\:[:alnum:]][!-\:[:alnum:]]b
a[!-\:[:alnum:]]b
POST-GLOB:
FILE #1: '?
\'
FILE #2: '?
^'
FILE #3: '?
`'
FILE #4: '[ \'
FILE #5: '[
\'
FILE #6: '] ^'
FILE #7: ']
^'
FILE #8: '_ `'
FILE #9: '_
`'
FILE #10: '?
b'
FILE #11: 'a b'
FILE #12: 'a
b'
Poniżej ponownie podchodzę do problemu, ale używam innej metodologii. Pamiętaj, że - oprócz \0
null - /
znak ASCII jest jedynym bajtem zabronionym w nazwie ścieżki. Odkładam globusy na bok i zamiast tego łączę -d
opcję określoną dla ls
POSIX i -exec $cmd {} +
konstrukcję określoną również dla POSIX find
. Ponieważ w find
naturalny sposób będzie emitować tylko jeden /
po kolei, poniższe elementy łatwo zdobywają rekurencyjną i rzetelnie ograniczoną listę plików, w tym wszystkie informacje o dentystyce dla każdego wpisu. Wyobraź sobie, co możesz zrobić z czymś takim:
#v#note: to do this fully portably substitute an actual newline \#v#
#v#for 'n' for the first sed invocation#v#
cd ..
find ././ -exec ls -1ldin {} + |
sed -e '\| *\./\./|{s||\n.///|;i///' -e \} |
sed 'N;s|\(\n\)///|///\1|;$s|$|///|;P;D'
###OUTPUT
152398 drwxr-xr-x 1 1000 1000 72 Jun 24 14:49
.///testls///
152399 -rw-r--r-- 1 1000 1000 0 Jun 24 14:49
.///testls/?
\///
152402 -rw-r--r-- 1 1000 1000 0 Jun 24 14:49
.///testls/?
^///
152405 -rw-r--r-- 1 1000 1000 0 Jun 24 14:49
.///testls/?
`///
...
ls -i
może być bardzo przydatny - zwłaszcza gdy kwestionowana jest wyjątkowość wyniku.
ls -1iq |
sed '/ .*/s///;s/^/-inum /;$!s/$/ -o /' |
tr -d '\n' |
xargs find
To tylko najbardziej przenośne środki, jakie mogę wymyślić. Z GNU ls
możesz:
ls --quoting-style=WORD
I na koniec, oto o wiele prostsza metoda parsowanials
, z której zdarza się dość często, gdy potrzebuję numerów i-węzłów:
ls -1iq | grep -o '^ *[0-9]*'
To tylko zwraca numery i-węzłów - co jest kolejną przydatną opcją określoną przez POSIX.
time bash -c 'for i in {1..1000}; do ls -R &>/dev/null; done'
= 3.18s vstime bash -c 'for i in {1..1000}; do echo **/* >/dev/null; done'
= 1.28sstat
w mojej odpowiedzi, ponieważ faktycznie sprawdza, czy każdy plik istnieje. Twój kawałek na dolesed
rzeczy nie działa.ls
? To, co opisujesz, jest bardzo trudne. Będę musiał go zdekonstruować, aby wszystko zrozumieć, a ja jestem stosunkowo kompetentnym użytkownikiem. Nie możesz oczekiwać, że przeciętny Joe będzie w stanie poradzić sobie z czymś takim.ls
danych wyjściowych jest nieprawidłowe, zostały dobrze omówione w oryginalnym łączu (oraz w wielu innych miejscach). To pytanie byłoby rozsądne, gdyby OP poprosił o pomoc w zrozumieniu go, ale zamiast tego OP próbuje po prostu udowodnić, że jego nieprawidłowe użycie jest w porządku.parsing ls is bad
. Robifor something in $(command)
i opierając się na słowo rozszczepienia, aby uzyskać dokładne wyniki są złe dla większości zcommand's
których nie mają proste wyjście.Odpowiedzi:
Nie jestem wcale przekonany o tym, ale załóżmy, że przez wzgląd na argument, że mógłby , jeśli jesteś przygotowany do wprowadzenia na tyle wysiłku, analizować wyjście
ls
niezawodnie, nawet w obliczu „przeciwnik” - kogoś, kto zna kod, który napisałeś i celowo wybiera nazwy plików zaprojektowane w celu jego złamania.Nawet gdybyś mógł to zrobić, byłby to zły pomysł .
Powłoka Bourne'a nie jest dobrym językiem. Nie należy go używać do niczego skomplikowanego, chyba że ekstremalna przenośność jest ważniejsza niż jakikolwiek inny czynnik (np
autoconf
.).Twierdzę, że jeśli masz do czynienia z problemem polegającym na tym, że analiza wyniku
ls
wydaje się ścieżką najmniejszego oporu dla skryptu powłoki, jest to mocna wskazówka, że cokolwiek robisz, jest zbyt skomplikowane dla powłoki i powinieneś przepisać całą rzecz w Perl lub Python. Oto twój ostatni program w Pythonie:Nie ma to żadnych problemów z nietypowymi znakami w nazwach plików - wynik jest niejednoznaczny w taki sam sposób, jak wynik
ls
jest niejednoznaczny, ale nie miałoby to znaczenia w „prawdziwym” programie (w przeciwieństwie do takiej wersji demo), co użyj wynikuos.path.join(subdir, f)
bezpośrednio.Równie ważne i w przeciwieństwie do tego, co napisałeś, nadal będzie miało sens za sześć miesięcy i będzie łatwe do zmodyfikowania, gdy będziesz potrzebować zrobić coś nieco innego. Dla ilustracji załóżmy, że odkryłeś potrzebę wykluczenia plików dotfiles i kopii zapasowych edytora oraz przetwarzania wszystkiego w kolejności alfabetycznej według basename:
źródło
for in | for in
mówi o rekurencji? Nie jestem pewny. Nawet jeśli tak, to nie może być więcej niż jeden, prawda? To jedyna jak dotąd sensowna dla mnie odpowiedź.for
pętle.os.walk
robi naprawdę ciężkie podnoszenie się za kulisy, ale nie musisz się o to martwić bardziej niż musisz się martwić o to, jakls
lubfind
pracować wewnętrznie.os.walk
zwraca obiekt generatora . Generatory to wersja leniwych list Pythona. Za każdym razem, gdy iteruje zewnętrzna pętla for, generator jest wywoływany i „dostarcza” zawartość innego podkatalogu. Równoważna funkcjonalność w Perlu toFile::Find
, jeśli to pomaga.ls
danych wyjściowych.Ten link jest często przywoływany, ponieważ informacje są całkowicie dokładne i istnieją już od bardzo dawna.
ls
zastępuje znaki niedrukowalne znakami glob tak, ale te znaki nie znajdują się w rzeczywistej nazwie pliku. Dlaczego to ma znaczenie? 2 powody:Na przykład:
Zauważ, że mamy 2 pliki, które wyglądają dokładnie tak samo. Jak zamierzasz je rozróżnić, jeśli oba są reprezentowane jako
a?b
?Jest tutaj różnica. Po odzyskaniu globu, jak pokazano, glob może pasować do więcej niż jednego pliku. Jednak podczas iteracji wyników pasujących do globu, otrzymujesz dokładnie ten plik, a nie glob.
Na przykład:
Zauważ, jak
xxd
pokazuje wynik$file
zawierający surowe znaki,\t
a\n
nie?
.Jeśli używasz
ls
, zamiast tego otrzymasz:„I tak zamierzam iterować, dlaczego nie użyć
ls
?”Twój przykład, który podałeś, w rzeczywistości nie działa. Wygląda na to, że działa, ale nie działa.
Mam na myśli to:
Utworzyłem katalog z wieloma nazwami plików:
Po uruchomieniu kodu otrzymuję:
Gdzie poszła reszta plików?
Spróbujmy zamiast tego:
Teraz użyjmy rzeczywistego globu:
Z uderzeniem
Powyższy przykład dotyczy mojej normalnej powłoki, zsh. Kiedy powtarzam procedurę z bash, otrzymuję inny zupełnie inny zestaw wyników z twoim przykładem:
Ten sam zestaw plików:
Radykalnie różne wyniki z Twoim kodem:
Dzięki powłoce glob działa idealnie dobrze:
Powód, dla którego bash zachowuje się w ten sposób, powraca do jednego z punktów, które podniosłem na początku odpowiedzi: „Glob pliku może pasować do więcej niż jednego pliku”.
ls
zwraca ten sam glob (a?b
) dla kilku plików, więc za każdym razem, gdy rozwijamy ten glob, otrzymujemy każdy pasujący do niego plik.Jak odtworzyć listę plików, których używałem:
Te w kodzie szesnastkowym są znakami NBSP UTF-8.
źródło
ls
. Poprosiłem również o przetestowanie kodu, ponieważ nie działa. Co Zsh ma wspólnego z tym wszystkim?Spróbujmy trochę uprościć:
Widzieć? To już tam źle. Istnieją 3 pliki, ale bash zgłasza 4. Jest tak, ponieważ
set
generowanels
są globusy, o które są one rozszerzane przez powłokę przed przekazaniem doset
. Dlatego otrzymujesz:Lub, jeśli wolisz:
Powyższe zostało uruchomione
bash 4.2.45
.źródło
ls -1qRi | grep -o '^ *[0-9]*'
- analizowaniels
danych wyjściowych, stary, i jest to najszybszy i najlepszy sposób, jaki znam, aby uzyskać listę numerów i-węzłów.Wynik
ls -q
nie jest globem. To?
oznacza „Jest tutaj postać, której nie można wyświetlić bezpośrednio”. Globs?
oznacza „Każda postać jest tutaj dozwolona”.Kule mają inne znaki specjalne (
*
a[]
przynajmniej, a wewnątrz[]
pary jest więcej). Żaden z nich nie uciekłls -q
.Jeśli potraktujesz
ls -1q
wynik, będziesz mieć zestaw globów i je rozszerzysz, nie tylko dostanieszx
dwa razy, ale[x]
całkowicie przegapisz . Jako glob nie pasuje do siebie jako ciąg znaków.ls -q
ma na celu uratować twoje oczy i / lub terminal przed szalonymi postaciami, a nie produkować coś, co możesz przekazać z powrotem do powłoki.źródło
Odpowiedź jest prosta: szczególne przypadki, w
ls
których musisz sobie poradzić, przewyższają wszelkie możliwe korzyści. Tych specjalnych przypadków można uniknąć, jeśli nie przeanalizujeszls
danych wyjściowych.Mantra tutaj nigdy nie ufa systemowi plików użytkownika (odpowiednik nigdy nie ufać wprowadzeniu przez użytkownika ). Jeśli istnieje metoda, która zawsze będzie działać, ze 100% pewnością, powinna to być metoda preferowana, nawet jeśli
ls
robi to samo, ale z mniejszą pewnością. Nie będę wchodził w szczegóły techniczne, ponieważ były one obszernie omówione przez Terdona i Patricka . Wiem, że ze względu na ryzyko związane z korzystaniemls
z ważnej (i być może drogiej) transakcji, w której moja praca / prestiż są na linii, wolę każde rozwiązanie, które nie ma stopnia niepewności, jeśli można tego uniknąć.Wiem, że niektórzy wolą ryzyko niż pewność , ale zgłosiłem błąd .
źródło
Powód, dla którego ludzie mówią, że nigdy czegoś nie robi, niekoniecznie jest konieczny, ponieważ absolutnie pozytywnie nie można tego zrobić poprawnie. Możemy to zrobić, ale może to być bardziej skomplikowane, mniej wydajne zarówno pod względem czasu, jak i przestrzeni. Na przykład idealnie byłoby powiedzieć „Nigdy nie buduj dużego zaplecza e-commerce w zestawie x86”.
Przejdźmy teraz do omawianego problemu: Jak wykazałeś, możesz stworzyć rozwiązanie, które analizuje ls i daje właściwy wynik - więc poprawność nie jest problemem.
Czy to jest bardziej skomplikowane? Tak, ale możemy to ukryć za funkcją pomocnika.
Teraz do wydajności:
Oszczędność miejsca: Twoje rozwiązanie polega na
uniq
odfiltrowaniu duplikatów, w związku z czym nie jesteśmy w stanie wygenerować wyników leniwie. Więc alboO(1)
kontraO(n)
albo oba mająO(n)
.Wydajność czasowa: Najlepszy przypadek
uniq
wykorzystuje podejście hashapowe, więc nadal mamyO(n)
algorytm liczby pozyskanych elementów , prawdopodobnie tak jestO(n log n)
.Teraz prawdziwy problem: chociaż twój algorytm wciąż nie wygląda tak źle, bardzo ostrożnie użyłem pozyskanych elementów, a nie elementów dla n. Ponieważ robi to dużą różnicę. Załóżmy, że masz plik,
\n\n
którego wynikiem będzie glob,??
więc dopasuj każdy 2-znakowy plik na liście. Zabawnie, jeśli masz inny plik\n\r
, który również spowoduje??
i zwróci wszystkie 2 pliki znaków. Widzisz, dokąd to zmierza? Zachowanie wykładnicze zamiast liniowego z pewnością kwalifikuje się jako „gorsze zachowanie w czasie wykonywania” .. to różnica między praktycznym algorytmem a tym, o którym piszesz artykuły w teoretycznych czasopismach CS.Wszyscy kochają przykłady, prawda? No to ruszamy. Utwórz folder o nazwie „test” i użyj tego skryptu python w tym samym katalogu, w którym znajduje się folder.
Jedyne, co to robi, to generowanie wszystkich produktów o długości 3 dla 7 znaków. Liceum matematyczne mówi nam, że powinny to być 343 pliki. To powinno być naprawdę szybkie do wydrukowania, więc zobaczmy:
Wypróbujmy teraz twoje pierwsze rozwiązanie, ponieważ naprawdę nie mogę tego dostać
rzecz tutaj do pracy na Linux mennicy 16 (która, jak myślę, mówi wiele o użyteczności tej metody).
W każdym razie, ponieważ powyższe właściwie filtruje wynik tylko po jego otrzymaniu, wcześniejsze rozwiązanie powinno być co najmniej tak szybkie jak później (nie ma w tym żadnych sztuczek i-węzłów - ale są one niewiarygodne, więc zrezygnujesz z poprawności).
Więc teraz, jak długo to trwa
brać? Naprawdę nie wiem, sprawdzenie nazw plików 343 ^ 343 zajmuje trochę czasu - powiem ci po śmierci wszechświata.
źródło
Podane intencje OP są adresowane
przedmowa i uzasadnienie oryginalnej odpowiedzi † zaktualizowane 18.05.2015
mikeserv (OP) stwierdził w najnowszej aktualizacji swojego pytania: „Uważam jednak za wstyd , że najpierw zadałem to pytanie, aby wskazać źródło dezinformacji, i, niestety, najbardziej pozytywna odpowiedź tutaj jest w dużej mierze myląca. „
No dobrze; Wydaje mi się, że to wstyd, że spędziłem tak dużo czasu, próbując wymyślić, jak wyjaśnić moje znaczenie, tylko po to, by je znaleźć , gdy ponownie przeczytałem pytanie. To pytanie zakończyło się „[generowaniem] dyskusji zamiast odpowiedzi” ‡ i ważyło około 18 000 tekstu (dla samego pytania, żeby było jasne), co byłoby długie nawet na blogu.
Ale StackExchange nie jest twoim mydłem i nie jest twoim blogiem. Jednak w rzeczywistości użyłeś go jako co najmniej jednego z nich. Ludzie spędzali dużo czasu, odpowiadając na twoje „To-Point-Out”, zamiast odpowiadać na rzeczywiste pytania ludzi. W tym miejscu będę oznaczać to pytanie jako niezbyt odpowiednie dla naszego formatu, biorąc pod uwagę, że PO wyraźnie stwierdził, że wcale nie miało być pytaniem.
W tym momencie nie jestem pewien, czy moja odpowiedź była istotna, czy nie; prawdopodobnie nie, ale był skierowany na niektóre z twoich pytań i może być użyteczną odpowiedzią dla kogoś innego; początkujący nabierają serca, niektórzy z tych „nie” zamieniają się w „czasem”, gdy zdobędziesz więcej doświadczenia. :)
Z reguły...
proszę wybaczyć pozostałe szorstkie krawędzie; spędziłem już na tym zbyt dużo czasu ... zamiast cytować bezpośrednio PO (jak pierwotnie zamierzałem) postaram się streścić i sparafrazować.
[w dużej mierze przerobione z mojej pierwotnej odpowiedzi]
po rozważeniu, uważam, że źle odczytałem nacisk, jaki PO kładzie na pytania, na które odpowiedziałem; Jednak poruszone kwestie zostały poruszone i pozostawiłem odpowiedzi w dużej mierze nietknięte, ponieważ uważam, że są one trafne i odnoszą się do problemów, które widziałem w innych kontekstach, a także odnośnie porad dla początkujących.
Oryginalny post pytał na kilka sposobów, dlaczego różne artykuły zawierały porady, takie jak „Nie analizuj
ls
danych wyjściowych” lub „Nigdy nie należy analizowaćls
danych wyjściowych” i tak dalej.Moim sugerowanym rozwiązaniem tego problemu jest to, że przypadki tego rodzaju stwierdzeń są po prostu przykładami idiomu, sformułowanego w nieco inny sposób, w którym kwantyfikator absolutny jest zestawiany z imperatywem [np. „Nie [nigdy] X”, «[Powinieneś] zawsze T», «[nie należy nigdy Z»] do formułowania oświadczeń, które mają być używane jako ogólne zasady lub wytyczne, zwłaszcza gdy są podawane tym, którzy są nowi w temacie, a nie jako absolutne prawdy, pomimo oczywistej formy tych oświadczeń.
Kiedy zaczynasz uczyć się nowych przedmiotów i jeśli nie masz dobrego zrozumienia, dlaczego możesz zrobić inaczej, dobrym pomysłem jest przestrzeganie ogólnie przyjętych zasad bez wyjątku - chyba że pod kierunkiem kogoś bardziej doświadczonego to ty. Wraz ze wzrostem umiejętności i doświadczenia możesz dalej określać, kiedy i czy reguła ma zastosowanie w konkretnej sytuacji. Gdy osiągniesz znaczny poziom doświadczenia, najprawdopodobniej zrozumiesz przede wszystkim uzasadnienie ogólnej reguły, a następnie możesz zacząć oceniać, czy i do jakiego poziomu uzasadnienie ma zastosowanie ta sytuacja, a także to, czy istnieją jakieś nadrzędne obawy.
I wtedy ekspert może zdecydować się na zrobienie czegoś z naruszeniem „Reguł”. Ale to nie uczyniłoby ich mniej „regułami”.
I tak do omawianego tematu: moim zdaniem, tylko dlatego, że ekspert może być w stanie złamać tę zasadę, nie dając się całkowicie obalić, nie widzę żadnego sposobu, aby usprawiedliwić mówienie nowicjuszowi, że „czasami” to jest dobrze przeanalizować
ls
dane wyjściowe, ponieważ: nie jest . A przynajmniej na pewno nie jest to odpowiednie dla początkujących.Zawsze stawiacie pionki na środku; na początku jeden kawałek, jeden ruch; zamek przy najbliższej okazji; rycerze przed biskupami; rycerz na brzegu jest ponury; i zawsze upewnij się, że do końca widzisz swoje obliczenia! (Ups, przepraszam, męczę się, to dla szachowej StackExchange.)
Zasady, które chcesz złamać?
Czytając artykuł na temat, który jest skierowany do początkujących lub prawdopodobnie zostanie przeczytany, często zobaczysz takie rzeczy:
Chociaż te stwierdzenia z pewnością wydają się określać bezwzględne i ponadczasowe reguły, nie są; zamiast tego jest to sposób określenia ogólnych zasad [aka „wytycznych”, „praktycznych zasad”, „podstaw” itp.], które są co najmniej prawdopodobnie jednym z odpowiednich sposobów na ich określenie dla początkujących, którzy mogą czytać te artykuły. Jednak tylko dlatego, że są one określone jako absolutne, zasady z pewnością nie wiążą specjalistów i ekspertów [którzy prawdopodobnie byli tymi, którzy podsumowali takie zasady w pierwszej kolejności, jako sposób na rejestrowanie i przekazywanie wiedzy zdobytej podczas powtarzania się problemy związane z ich konkretnym rzemiosłem.]
Reguły te z pewnością nie ujawnią, w jaki sposób ekspert poradziłby sobie ze złożonym lub szczegółowym problemem, w którym powiedzmy, reguły te są ze sobą sprzeczne; lub w których obawy, które doprowadziły do reguły, po prostu nie mają zastosowania. Eksperci nie boją się (lub nie powinni się bać!) Po prostu łamać zasady, o których wiedzą, że nie mają sensu w konkretnej sytuacji. Eksperci nieustannie zajmują się równoważeniem różnych ryzyk i obaw w swoim rzemiośle i często muszą opierać się na swojej ocenie, aby złamać tego rodzaju reguły, muszą zrównoważyć różne czynniki i nie mogą polegać jedynie na tabeli reguł, których muszą przestrzegać. Weźmy
Goto
jako przykład: długa, powtarzająca się debata na temat tego, czy są szkodliwe. (Tak, nigdy nie używaj gotów; D)Propozycja modalna
Dziwną cechą, przynajmniej po angielsku, i wyobrażam sobie w wielu innych językach, ogólne zasady, jest to, że są one podane w tej samej formie co propozycja modalna, ale eksperci w danej dziedzinie są gotowi podać ogólną regułę dla sytuacja, cały czas wiedząc, że w razie potrzeby złamią zasadę. Oczywiste jest zatem, że te instrukcje nie mają być równoważne z tymi samymi instrukcjami w logice modalnej.
Dlatego mówię, że muszą być po prostu idiomatyczni. Zamiast naprawdę być sytuacją „nigdy” lub „zawsze”, reguły te służą zwykle kodyfikacji ogólnych wytycznych, które są odpowiednie w szerokim zakresie sytuacji i które, gdy początkujący postępują zgodnie z nimi na ślepo, mogą doprowadzić do daleko lepsze wyniki niż początkujący decydujący się na nie bez powodu. Czasami kodyfikują reguły, co po prostu prowadzi do niespełniających norm wyników, a nie do oczywistych niepowodzeń towarzyszących nieprawidłowym wyborom niezgodnym z regułami.
Zatem ogólne reguły nie są absolutnymi propozycjami modalnymi, które wydają się znajdować na powierzchni, ale zamiast tego są skrótowym sposobem nadania reguły z domyślnym standardowym szablonem, coś w rodzaju:
gdzie oczywiście można zastąpić „nigdy nie analizuj
ls
danych wyjściowych” zamiast $ {RULE}. :)O tak! Co O Analizowanie
ls
wyjście?Cóż, biorąc pod uwagę to wszystko ... myślę, że jest całkiem jasne, że ta zasada jest dobra. Po pierwsze, prawdziwą zasadę należy rozumieć jako idiomatyczną, jak wyjaśniono powyżej ...
Co więcej, nie chodzi tylko o to, że musisz bardzo dobrze posługiwać się skryptami powłoki, aby wiedzieć, czy w niektórych przypadkach można go złamać. Trzeba też tyle samo umiejętności, by powiedzieć, że się pomyliłeś, kiedy próbujesz przerwać testowanie! I mówię z przekonaniem, że bardzo duża część prawdopodobnych odbiorców takich artykułów (udzielających porad typu „Nie analizuj wyników
ls
!”) Nie może robić tych rzeczy , a ci, którzy posiadają takie umiejętności, prawdopodobnie zdadzą sobie z tego sprawę. wymyślają to sami i i tak ignorują zasadę.Ale ... spójrz tylko na to pytanie i jak nawet osoby, które prawdopodobnie mają taką umiejętność, sądziły, że to zły telefon; i ile wysiłku autor pytania poświęcił właśnie temu, aby dotrzeć do punktu obecnego najlepszego przykładu! Gwarantuję ci problem, który ciężko, 99% ludzi pomyliłoby się i przyniosłoby potencjalnie bardzo złe rezultaty! Nawet jeśli wybrana metoda okaże się dobra; dopóki ten (lub inny)
ls
pomysł analizowania nie zostanie przyjęty przez ogół informatyków / programistów jako całość, wytrzyma wiele testów (zwłaszcza próby czasu) i wreszcie uda mu się przejść do statusu „wspólnej techniki”, jest prawdopodobne, że wiele osób może tego spróbować i źle się pomylić ... z katastrofalnymi konsekwencjami.Tak, będę powtarzać po raz ostatni .... że, zwłaszcza w tym przypadku , że właśnie dlatego „ nigdy analizować
ls
wyjście!” jest zdecydowanie właściwym sposobem na wyrażenie tego.[AKTUALIZACJA 2014-05-18: wyjaśnienie uzasadnienia odpowiedzi (powyżej) w celu udzielenia odpowiedzi na komentarz PO; następujący dodatek jest odpowiedzią na uzupełnienia PO do pytania z wczoraj]
[AKTUALIZACJA 2014-11-10: dodano nagłówki i przeorganizowano / przeredagowano treść; a także: przeformatowanie, przeredagowanie, wyjaśnienie i um ... „zwięzłe rozwikłanie” ... chciałem, żeby to było po prostu porządek, choć przerodziło się to w trochę przeróbki. pozostawiłem go w opłakanym stanie, więc głównie starałem się go uporządkować. czułem, że ważne jest, aby w dużej mierze pozostawić pierwszą część nienaruszoną; więc tylko dwie niewielkie zmiany, zbędne „ale” usunięte, a „to” podkreślone.]
† Pierwotnie zamierzałem to wyłącznie jako wyjaśnienie mojego oryginału; ale zdecydował o innych dodatkach po refleksji
‡ Zobacz https://unix.stackexchange.com/tour, aby uzyskać wskazówki dotyczące postów
źródło
ls
!” jest poprawna rada: 1. wykazać (w sposób zadowalający), że każdy przypadek użycia, w którym można przeanalizowaćls
dane wyjściowe, ma inne dostępne rozwiązanie, w pewien sposób lepsze, bez robienia tego. 2. pokazać, że w cytowanych przypadkach stwierdzenie nie jest dosłowne.ls
to narzędzie komputerowe - możesz analizować dane wyjściowe komputera.Czy
ls
w niektórych przypadkach można przeanalizować dane wyjściowe ? Pewnie. Pomysł wyodrębnienia listy numerów i-węzłów z katalogu jest dobrym przykładem - jeśli wiesz, że twoja implementacjals
obsługuje-q
, a zatem każdy plik wygeneruje dokładnie jeden wiersz danych wyjściowych, a wszystko, czego potrzebujesz, to liczby i-węzłów, parsując je zls -Rai1q
wyjście jest z pewnością możliwym rozwiązaniem. Oczywiście, gdyby autor nie widział wcześniej porady typu „Nigdy nie analizuje wyniku ls”, prawdopodobnie nie pomyślałby o nazwach plików z nowymi liniami i prawdopodobnie w rezultacie pomijałby „q”, a kod byłby subtelnie uszkodzony w tym przypadku krawędzi - więc nawet w przypadkach, w których wynik parsowanials
jest rozsądny, ta rada jest nadal przydatna.Szerszy Chodzi o to, że gdy początkującym zapłacić włączony stara się mieć postać skryptu z (na przykład), co jest największym pliku w katalogu, lub co ostatnio zmodyfikowany plik w katalogu, jego pierwszym odruchem jest do analizowania
ls
„s wyjście - zrozumiałe, ponieważls
jest to jedno z pierwszych poleceń, których uczy się początkujący.Niestety, ten instynkt jest zły, a podejście to jest zepsute. Co więcej, jest subtelnie zepsuty - będzie działał przez większość czasu, ale zawiedzie w skrajnych przypadkach, które być może mogłyby zostać wykorzystane przez osobę znającą kod.
Początkujący może myśleć o
ls -s | sort -n | tail -n 1 | awk '{print $2}'
sposobie uzyskania największego pliku w katalogu. I działa, dopóki nie masz pliku ze spacją w nazwie.OK, a co powiesz na
ls -s | sort -n | tail -n 1 | sed 's/[^ ]* *[0-9]* *//'
? Działa dobrze, dopóki nie masz pliku z nową linią w nazwie.Czy dodanie
-q
dols
„s argumenty pomóc, gdy nie jest to znak nowej linii w pliku? Może tak wyglądać, dopóki nie będziesz mieć 2 różnych plików, które zawierają znak, który nie może być wydrukowany, w tym samym miejscu w nazwie pliku, a wtedyls
wynik nie pozwoli ci rozróżnić, który z nich był największy. Co gorsza, aby rozwinąć „?”, Prawdopodobnie ucieka się do swojej powłokieval
- co spowoduje problemy, jeśli trafi na plik o nazwie na przykład,Czy
--quoting-style=shell
pomaga (jeśli wls
ogóle go wspierasz)? Nie, nadal wyświetla? dla znaków niedrukowalnych, więc nadal nie jest jasne, który z wielu dopasowań był największy.--quoting-style=literal
? Nie, to samo.--quoting-style=locale
lub--quoting-style=c
może pomóc, jeśli po prostu potrzebujesz jednoznacznie wydrukować nazwę największego pliku, ale prawdopodobnie nie, jeśli później musisz coś zrobić z plikiem - to byłoby mnóstwo kodu, aby cofnąć cytowanie i wrócić do prawdziwej nazwy pliku, więc że możesz przekazać to, powiedzmy, gzip.I pod koniec całej tej pracy, nawet jeśli to, co ma, jest bezpieczne i poprawne dla wszystkich możliwych nazw plików, jest nieczytelne i niemożliwe do utrzymania, i można było to zrobić o wiele łatwiej, bezpieczniej i łatwiej w Pythonie, Perlu lub Rubinie.
A nawet używając innych narzędzi powłoki - myślę, że to powinno załatwić sprawę:
I powinien być przynajmniej tak przenośny, jak
--quoting-style
jest.źródło