Dlaczego * nie * parsuje `ls` (i co zamiast tego zrobić)?

204

Konsekwentnie widzę odpowiedzi cytujące ten link stwierdzające definitywnie: „Nie analizuj ls!” Niepokoi mnie to z kilku powodów:

  1. 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.

  2. 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. ... lsoddziela 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, lsktóra pozwala na zakończenie nazw plików ze znakami NUL zamiast znaków nowej linii, nie możemy bezpiecznie uzyskać listy nazw plików ls.

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ść lsimplementacji 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 lsczasami garbles dane pliku (w naszym przypadku okazało się \npostać 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 forpętli i globu:

for f in *; do
    [[ -e $f ]] || continue
    ...
done

Autor nazywa to mylącymi nazwami plików, gdy lszwraca 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 lsOperandy 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 lswyniki 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 zshpotem 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_SPLITzmienną podczas używania zshi 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 -uliście dla wyjątkowych rezultatów. Jest to bezpieczne, ponieważ lsma 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 \0null - /znak ASCII jest jedynym bajtem zabronionym w nazwie ścieżki. Odkładam globusy na bok i zamiast tego łączę -dopcję określoną dla lsPOSIX i -exec $cmd {} +konstrukcję określoną również dla POSIX find. Ponieważ w findnaturalny 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 lsmoż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.

mikeserv
źródło
12
@mikeserv Ok zrobiłem. Shell glob jest 2,48 razy szybszy. time bash -c 'for i in {1..1000}; do ls -R &>/dev/null; done'= 3.18s vs time bash -c 'for i in {1..1000}; do echo **/* >/dev/null; done'= 1.28s
Patrick
28
Jeśli chodzi o twoją najnowszą aktualizację, przestań polegać na wynikach wizualnych, ponieważ określasz, czy Twój kod działa. Przekaż dane wyjściowe do rzeczywistego programu i poproś go, aby spróbował wykonać operację na pliku. Właśnie dlatego użyłem statw mojej odpowiedzi, ponieważ faktycznie sprawdza, czy każdy plik istnieje. Twój kawałek na dole sedrzeczy nie działa.
Patrick
57
Nie możesz mówić poważnie. Jak przeskakiwanie przez wszystkie obręcze, które opisuje twoje pytanie, może być łatwiejsze, prostsze lub w jakikolwiek sposób lepsze niż po prostu nie analizowanie 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.
terdon
46
-1 za użycie pytania do wybrania argumentu. Wszystkie powody, dla których parsowanie lsdanych 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.
R ..
14
@mikeserv To nie tylko to parsing ls is bad. Robi for something in $(command)i opierając się na słowo rozszczepienia, aby uzyskać dokładne wyniki są złe dla większości z command'sktórych nie mają proste wyjście.
BroSlow

Odpowiedzi:

184

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 lsniezawodnie, 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 lswydaje 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:

import os, sys
for subdir, dirs, files in os.walk("."):
    for f in dirs + files:
      ino = os.lstat(os.path.join(subdir, f)).st_ino
      sys.stdout.write("%d %s %s\n" % (ino, subdir, f))

Nie ma to żadnych problemów z nietypowymi znakami w nazwach plików - wynik jest niejednoznaczny w taki sam sposób, jak wynik lsjest niejednoznaczny, ale nie miałoby to znaczenia w „prawdziwym” programie (w przeciwieństwie do takiej wersji demo), co użyj wyniku os.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:

import os, sys
filelist = []
for subdir, dirs, files in os.walk("."):
    for f in dirs + files:
        if f[0] == '.' or f[-1] == '~': continue
        lstat = os.lstat(os.path.join(subdir, f))
        filelist.append((f, subdir, lstat.st_ino))

filelist.sort(key = lambda x: x[0])
for f, subdir, ino in filelist: 
   sys.stdout.write("%d %s %s\n" % (ino, subdir, f))
zwol
źródło
5
To jest dobre. Czy to for in | for inmó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ź.
mikeserv
10
Brak rekurencji, po prostu zagnieżdżone forpętle. os.walkrobi naprawdę ciężkie podnoszenie się za kulisy, ale nie musisz się o to martwić bardziej niż musisz się martwić o to, jak lslub findpracować wewnętrznie.
zwolnienie
6
Technicznie os.walkzwraca 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 to File::Find, jeśli to pomaga.
zwolnienie
6
Powinieneś zdawać sobie sprawę, że w 100% zgadzam się z dokumentem, który krytykujesz, i odpowiedziami Patricka i Terdona. Moja odpowiedź miała na celu dostarczenie dodatkowego , niezależnego powodu, aby uniknąć parsowania lsdanych wyjściowych.
zwolnienie
19
To jest bardzo mylące. Shell nie jest dobrym językiem programowania, ale tylko dlatego, że nie jest językiem programowania. To język skryptowy. I to jest dobry język skryptowy.
Miles Rout
178

Ten link jest często przywoływany, ponieważ informacje są całkowicie dokładne i istnieją już od bardzo dawna.


lszastępuje znaki niedrukowalne znakami glob tak, ale te znaki nie znajdują się w rzeczywistej nazwie pliku. Dlaczego to ma znaczenie? 2 powody:

  1. Jeśli przekażesz tę nazwę pliku do programu, ta nazwa pliku faktycznie nie istnieje. Musi rozwinąć glob, aby uzyskać prawdziwą nazwę pliku.
  2. Glob pliku może być zgodny z więcej niż jednym plikiem.

Na przykład:

$ touch a$'\t'b
$ touch a$'\n'b
$ ls -1
a?b
a?b

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?


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!

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:

$ for file in *; do printf '%s' "$file" | xxd; done
0000000: 6109 62                                  a.b
0000000: 610a 62                                  a.b

Zauważ, jak xxdpokazuje wynik $filezawierający surowe znaki, \ta \nnie ?.

Jeśli używasz ls, zamiast tego otrzymasz:

for file in $(ls -1q); do printf '%s' "$file" | xxd; done
0000000: 613f 62                                  a?b
0000000: 613f 62                                  a?b

„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:

 for f in $(ls -1q | tr " " "?") ; do [ -f "$f" ] && echo "./$f" ; done

Utworzyłem katalog z wieloma nazwami plików:

$ for file in *; do printf '%s' "$file" | xxd; done
0000000: 6120 62                                  a b
0000000: 6120 2062                                a  b
0000000: 61e2 8082 62                             a...b
0000000: 61e2 8083 62                             a...b
0000000: 6109 62                                  a.b
0000000: 610a 62                                  a.b

Po uruchomieniu kodu otrzymuję:

$ for f in $(ls -1q | tr " " "?") ; do [ -f "$f" ] && echo "./$f" ; done
./ab
./ab

Gdzie poszła reszta plików?

Spróbujmy zamiast tego:

$ for f in $(ls -1q | tr " " "?") ; do stat --format='%n' "./$f"; done
stat: cannot stat ‘./a?b’: No such file or directory
stat: cannot stat ‘./a??b’: No such file or directory
./ab
./ab
stat: cannot stat ‘./a?b’: No such file or directory
stat: cannot stat ‘./a?b’: No such file or directory

Teraz użyjmy rzeczywistego globu:

$ for f in *; do stat --format='%n' "./$f"; done
./a b
./a  b
./ab
./ab
./a b
./a
b

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:

$ for file in *; do printf '%s' "$file" | xxd; done
0000000: 6120 62                                  a b
0000000: 6120 2062                                a  b
0000000: 61e2 8082 62                             a...b
0000000: 61e2 8083 62                             a...b
0000000: 6109 62                                  a.b
0000000: 610a 62                                  a.b

Radykalnie różne wyniki z Twoim kodem:

for f in $(ls -1q | tr " " "?") ; do stat --format='%n' "./$f"; done
./a b
./ab
./ab
./a b
./a
b
./a  b
./ab
./ab
./a b
./ab
./ab
./a b
./a
b
./a b
./ab
./ab
./a b
./a
b

Dzięki powłoce glob działa idealnie dobrze:

$ for f in *; do stat --format='%n' "./$f"; done
./a b
./a  b
./ab
./ab
./a b
./a
b

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”.

lszwraca 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:

touch 'a b' 'a  b' a$'\xe2\x80\x82'b a$'\xe2\x80\x83'b a$'\t'b a$'\n'b

Te w kodzie szesnastkowym są znakami NBSP UTF-8.

Patrick
źródło
5
@ mikeserv faktycznie jego rozwiązanie nie zwraca globu. Właśnie zaktualizowałem odpowiedź, aby wyjaśnić tę kwestię.
Patrick
18
„Nie reszta”? To niespójne zachowanie i nieoczekiwane rezultaty, dlaczego to nie jest powód?
Patrick
11
@mikeserv Nie widziałeś mojego komentarza do twojego pytania? Globowanie skorupy jest 2,5 razy szybsze niż ls. Poprosiłem również o przetestowanie kodu, ponieważ nie działa. Co Zsh ma wspólnego z tym wszystkim?
Patrick,
27
@mikeserv Nie, to wszystko nadal dotyczy nawet bash. Skończyłem z tym pytaniem, ponieważ nie słuchasz tego, co mówię.
Patrick
7
Wiesz co, myślę , że poprę tę odpowiedź i wyjaśnię w moim, że zgadzam się ze wszystkim, co ona mówi. ;-)
zwolnić
54

Spróbujmy trochę uprościć:

$ touch a$'\n'b a$'\t'b 'a b'
$ ls
a b  a?b  a?b
$ IFS="
"
$ set -- $(ls -1q | uniq)
$ echo "Total files in shell array: $#"
Total files in shell array: 4

Widzieć? To już tam źle. Istnieją 3 pliki, ale bash zgłasza 4. Jest tak, ponieważ setgenerowane lssą globusy, o które są one rozszerzane przez powłokę przed przekazaniem do set. Dlatego otrzymujesz:

$ for x ; do
>     printf 'File #%d: %s\n' $((i=$i+1)) "$x"
> done
File #1: a b
File #2: a b
File #3: a    b
File #4: a
b

Lub, jeśli wolisz:

$ printf ./%s\\0 "$@" |
> od -A n -c -w1 |
> sed -n '/ \{1,3\}/s///;H
> /\\0/{g;s///;s/\n//gp;s/.*//;h}'
./a b
./a b
./a\tb
./a\nb

Powyższe zostało uruchomione bash 4.2.45.

terdon
źródło
2
Głosowałem za tym. Dobrze jest widzieć, jak gryzie cię własny kod. Ale to, że źle to zrozumiałem, nie oznacza, że ​​nie da się tego zrobić dobrze. Pokazałem wam bardzo prosty sposób na zrobienie tego dziś rano ls -1qRi | grep -o '^ *[0-9]*'- analizowanie lsdanych wyjściowych, stary, i jest to najszybszy i najlepszy sposób, jaki znam, aby uzyskać listę numerów i-węzłów.
mikeserv
38
@mikeserv: Można to zrobić dobrze, jeśli masz czas i cierpliwość. Ale w rzeczywistości jest on podatny na błędy. Źle to zrozumiałeś. kłócąc się o jego zalety! To ogromne uderzenie, jeśli nawet jedna osoba walcząca o to nie zrobi tego poprawnie. I są szanse, że prawdopodobnie poświęcisz więcej czasu na pomyłkę, zanim to zrobisz. Nie wiem o tobie, ale większość ludzi lepiej radzi sobie ze swoim czasem niż bawić się od wieków z tym samym wierszem kodu.
cHao
@ cHao - nie kłóciłem się o jego zalety - zaprotestowałem przeciwko jego propagandzie.
mikeserv
16
@mikeserv: Argumenty przeciwko niemu są uzasadnione i zasłużone. Nawet ty pokazałeś, że są prawdziwe.
cHao
1
@cHao - nie zgadzam się. Między mantrą a mądrością istnieje niezbyt dobra granica.
mikeserv
50

Wynik ls -qnie 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.

$ touch x '[x]'
$ ls -1q
[x]
x

Jeśli potraktujesz ls -1qwynik, będziesz mieć zestaw globów i je rozszerzysz, nie tylko dostaniesz xdwa 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
42

Odpowiedź jest prosta: szczególne przypadki, w lsktórych musisz sobie poradzić, przewyższają wszelkie możliwe korzyści. Tych specjalnych przypadków można uniknąć, jeśli nie przeanalizujesz lsdanych 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 lsrobi 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 korzystaniem lsz 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 .

Braiam
źródło
33

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 uniqodfiltrowaniu duplikatów, w związku z czym nie jesteśmy w stanie wygenerować wyników leniwie. Więc albo O(1)kontra O(n)albo oba mają O(n).

Wydajność czasowa: Najlepszy przypadek uniqwykorzystuje podejście hashapowe, więc nadal mamy O(n)algorytm liczby pozyskanych elementów , prawdopodobnie tak jest O(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\nktó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.

#!/usr/bin/env python3
import itertools
dir = "test/"
filename_length = 3
options = "\a\b\t\n\v\f\r"

for filename in itertools.product(options, repeat=filename_length):
        open(dir + ''.join(filename), "a").close()

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:

time for f in *; do stat --format='%n' "./$f" >/dev/null; done
real    0m0.508s
user    0m0.051s
sys 0m0.480s

Wypróbujmy teraz twoje pierwsze rozwiązanie, ponieważ naprawdę nie mogę tego dostać

eval set -- $(ls -1qrR ././ | tr ' ' '?' |
sed -e '\|^\(\.\{,1\}\)/\.\(/.*\):|{' -e \
        's//\1\2/;\|/$|!s|.*|&/|;h;s/.*//;b}' -e \
        '/..*/!d;G;s/\(.*\)\n\(.*\)/\2\1/' -e \
        "s/'/'\\\''/g;s/.*/'&'/;s/?/'[\"?\$IFS\"]'/g" |
uniq)

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

time for f in $(ls -1q | tr " " "?") ; do stat --format='%n' "./$f" >/dev/null; done

brać? Naprawdę nie wiem, sprawdzenie nazw plików 343 ^ 343 zajmuje trochę czasu - powiem ci po śmierci wszechświata.

Voo
źródło
6
Oczywiście, jak wspomniano w komentarzach pod inną odpowiedzią , stwierdzenie „... wykazałeś, że możesz stworzyć rozwiązanie, które analizuje ls i daje właściwy wynik ...” nie jest w rzeczywistości prawdą.
Wildcard
26

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 lsdanych wyjściowych” lub „Nigdy nie należy analizować lsdanych 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ć lsdane 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:

  • „Nie powinno się nigdy robić X.”
  • „Nigdy nie rób Q!”
  • „Nie rób Z.”
  • „Zawsze należy robić Y!”
  • „C, bez względu na wszystko”.

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 Gotojako 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:

chyba że masz możliwość stwierdzenia, że ​​te wytyczne są niepoprawne w konkretnym przypadku i udowodnienia sobie, że masz rację, to $ {ZASADA}

gdzie oczywiście można zastąpić „nigdy nie analizuj lsdanych wyjściowych” zamiast $ {RULE}. :)

O tak! Co O Analizowanie lswyjś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) lspomysł 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ć lswyjś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

shelleybutterfly
źródło
2
Nigdy nie jest idiomatyczny. To nie jest odpowiedź na nic.
mikeserv
1
Hmm Cóż, nie wiedziałem, czy ta odpowiedź będzie satysfakcjonująca, ale absolutnie nie spodziewałem się, że będzie kontrowersyjna . I nie (nie chciałem) argumentować, że „nigdy” nie było samo w sobie idiomatyczne; ale to „Nigdy nie rób X!” jest idiomatycznym zastosowaniem . Widzę dwa ogólne przypadki, które mogą pokazać, że „Nigdy / nie analizuj ls!” jest poprawna rada: 1. wykazać (w sposób zadowalający), że każdy przypadek użycia, w którym można przeanalizować lsdane 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.
shelleybutterfly
Patrząc ponownie na twoje pytanie, widzę, że najpierw wspominasz „nie ...”, a nie „nigdy ...”, co dobrze wpisuje się w twoją analizę, więc wyjaśnię również tę kwestię. W tym momencie istnieje już rozwiązanie pierwszego typu, które najwyraźniej zostało zademonstrowane / wyjaśnione w sposób satysfakcjonujący dla ciebie, więc nie zagłębię się w to zbytnio. Spróbuję jednak wyjaśnić nieco moją odpowiedź: tak jak mówię, nie starałem się być kontrowersyjny (lub konfrontacyjny!), Ale wskazałem, w jaki sposób te oświadczenia są ogólnie zamierzone.
shelleybutterfly
1
Powinienem posprzątać ten post. Mimo to, nigdy nie jest nie właściwa droga do wyrażenia go. To trochę niedorzeczne, że ludzie uważają, że mają kwalifikacje do mówienia innym nigdy lub nie - po prostu powiedz im, że nie uważasz, że to zadziała i dlaczego, ale wiesz, co zadziała i dlaczego. lsto narzędzie komputerowe - możesz analizować dane wyjściowe komputera.
mikeserv
1
Cóż, odwróciłem moje zdanie, ponieważ przynajmniej masz rację co do oflagowania. Spróbuję to posprzątać dziś wieczorem lub jutro. Myślę, że przeniosę większość przykładów kodu do odpowiedzi. Jednak nadal nie usprawiedliwia to nieścisłości w często cytowanym blogu. Chciałbym, żeby ludzie przestali w ogóle cytować instrukcję bash - przynajmniej nie po tym, jak zacytowali specyfikacje POSIX ...
mikeserv
16

Czy lsw 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 implementacja lsobsł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 z ls -Rai1qwyjś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 parsowania lsjest 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ż lsjest 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 -qdo ls„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 wtedy lswynik nie pozwoli ci rozróżnić, który z nich był największy. Co gorsza, aby rozwinąć „?”, Prawdopodobnie ucieka się do swojej powłoki eval- co spowoduje problemy, jeśli trafi na plik o nazwie na przykład,

foo`/tmp/malicious_script`bar

Czy --quoting-style=shellpomaga (jeśli w lsogó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=localelub --quoting-style=cmoż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ę:

find . -type f -printf "%s %f\0" | sort -nz | awk 'BEGIN{RS="\0"} END{sub(/[0-9]* /, "", $0); print}'

I powinien być przynajmniej tak przenośny, jak --quoting-stylejest.

godlygeek
źródło
Och, prawda o rozmiarze - prawdopodobnie mógłbym to zrobić, gdybym spróbował - powinienem? Im trochę zmęczony albo cała ta sprawa - Lubię swoją odpowiedź, ponieważ nie mów nie mogą lub nie lub nie , ale w rzeczywistości może podać przykłady dlaczego nie i porównywalne jak inaczej - dziękuję.
mikeserv
Myślę, że gdybyś spróbował, odkryłbyś, że jest to o wiele trudniejsze niż myślisz. Tak, polecam spróbować. Z przyjemnością będę podawać nazwy plików, które będą dla ciebie złamane tak długo, jak będę mógł o nich myśleć. :)
godlygeek
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
terdon
@mikeserv i godlygeek, przeniosłem ten wątek komentarza na czat . Proszę, nie miej takich długich dyskusji w komentarzach, po to jest czat.
terdon