Czy w nazwie pliku nie ma miejsca?

31

Mówi się, że w Unixie i Linuksie należy unikać spacji w nazwie pliku (zwykły plik, katalog, link, plik urządzenia, ...).

Ale robię to cały czas. W przypadku nazwy pliku ze spacją w środku,

  • W Nautilus znak spacji jest pokazany jako spacja.
  • W terminalu Bash albo używam \ do reprezentowania spacji, albo umieszczam nazwę pliku w parze podwójnych cudzysłowów.
  • w plikach niektórych aplikacji (Nautilus, nie jestem pewien, czy system operacyjny to zrobi), nazwa pliku jest zapisywana z zastąpioną spacją %20.

Czy spacja w nazwie pliku jest naprawdę niedozwolona?

Jak prawidłowo używasz lub radzisz sobie ze spacją w nazwie pliku?

Tim
źródło
17
Jest to dozwolone, ale jest naprawdę bardzo denerwujące. Nie ma tego powodu. Nie rób tego
Wyścigi lekkości z Moniką
3
Możesz także utworzyć pliki o nazwie -rf ~(użyj touch -- "-rf ~"), ale nie poleciłbym tego.
Ian D. Scott
5
Możesz to zrobić, jest to dozwolone, jak tworzenie skryptu autodestrukcji o nazwie „cd”, ale nie powinieneś tego robić. Twój plik już wygląda inaczej w 3 różnych narzędziach, czy to nie jest wystarczająco złe?
Falco
7
Nie wszyscy podzielają opinię, że to naprawdę, naprawdę denerwujące. A „Nie ma tego powodu” jest tak oczywiste, że nie wymaga obalenia. Poddałem się i nauczyłem, jak właściwie obchodzić się ze spacjami wiele lat temu, i w przeważającej części to naprawdę nic wielkiego.
2
@snailboat Spaces są objawem prawdziwego problemu, jakim jest brak standaryzacji. Uniksowe systemy plików pozwalają „nazwom” plików na niemal nieograniczone binarne obiekty BLOB. Jedynymi niedozwolonymi bajtami są 0 i 47 ( /separator). Wykorzystanie wszystkich 254 pozostałych bajtów otwiera drzwi do wszystkich sposobów niewypowiedzianych eldritchowych „nazw”. Oczywiście jest to szalone, ale nie wszyscy zgadzają się co do tego, co jest „rozsądne”, a różne postacie będą łamać różne narzędzia. Przecięcie zdrowego rozsądku wszystkich jest dość małe .
jw013,

Odpowiedzi:

48

Spacje, a nawet każda postać oprócz /NUL, są dozwolone w nazwach plików. Zalecenie, aby nie używać spacji w nazwach plików, wiąże się z niebezpieczeństwem, że mogą zostać źle zinterpretowane przez oprogramowanie, które źle je obsługuje. Prawdopodobnie takie oprogramowanie jest wadliwe. Ale prawdopodobnie również języki programowania, takie jak skrypty powłoki, sprawiają, że pisanie oprogramowania, które psuje się, gdy zawiera nazwy plików ze spacjami, sprawia, że ​​jest to zbyt łatwe. Błędy te często się prześlizgują, ponieważ skrypty powłoki nie są często testowane przez programistów używających nazw plików ze spacjami w im.

Zastępowane spacje %20nie są często widoczne w nazwach plików. Jest to najczęściej używane w przypadku adresów URL (internetowych). Chociaż prawdą jest, że kodowanie% z adresów URL czasami trafia do nazw plików, często przypadkowo.

Celada
źródło
6
Jest to „kodowanie adresów URL” lub „kodowanie procentowe” en.wikipedia.org/wiki/URL_encoding W związku z tym najbardziej odpowiednią nazwą jest prawdopodobnie „kodowanie URI”, ale ludzie uważają adres URL za łatwiejszy do powiedzenia niż URI , więc jest to powszechna forma błędna nazwa. Zauważ, że zestaw znaków zastrzeżonych w URI jest większy niż dla nazw plików * nix.
goldilocks
1
@Tim Nie wiem, czy możesz podać znak NUL w dowolnym argumencie wiersza poleceń w bash. Próbowałem kilku rzeczy, takich jak cytowanie go za pomocą Ctrl-V i coś podobnego, $(echo -e \\0)ale to nie działało. Chodzi o to, że NUL nie może być używany w nazwach plików, ponieważ nie można go używać w ciągach C (ponieważ jest to terminator ciągów), a wszystkie podstawowe interfejsy API, a także praktycznie wszystkie ciągi obsługiwane przez programy C używają tego formatu . Ponieważ bashjest napisane w C, może po prostu nie mieć żadnego wsparcia dla łańcuchów z NUL. Mogę się mylić, może być jakiś niejasny sposób ...
Celada
1
Rodzaj zależy od kontekstu. Funkcje łańcuchowe na ogół nie liczą końcowego null (a raczej pierwszy null jest końcem łańcucha, nawet jeśli po nim są jakieś rzeczy), więc w tym sensie ma zerową długość i dlatego byłby uważany za pusty.
goldilocks
3
@Celada oczywiście możesz używać NULi walić , potrzebujesz $'\0'. Na przykład:find . -print0 | while read -d $'\0' f; do echo "$f"; done
terdon
1
@goldilocks Czy ludzie faktycznie wymawiają URL jako „url”, mniej więcej rymuje się z „Earl”?
Miles Rout
17

Jak zauważyłeś, spacje dozwolone w nazwach plików.

Jeśli spojrzysz na pozycję „większość systemów plików UNIX” na tym wykresie w Wikipedii , zauważysz:

  • Dowolny 8-bitowy zestaw znaków jest dozwolony. Możemy również przejąć 7-bitowy kod ASCII pod tym parasolem, ponieważ jest on podzbiorem różnych zestawów 8-bitowych i zawsze jest implementowany przy użyciu 8 bitów.

  • Jedynymi zabronionymi postaciami są /„null”. „Null” odnosi się do bajtu zerowego, ale i tak nie są one dozwolone w danych tekstowych.

Jeśli jednak skorzystasz z powłoki, możesz zdać sobie sprawę, że istnieją pewne postacie, które spowodują kłopot, a co najważniejsze *, jest operatorem globowania POSIX.

W zależności od tego, jak chcesz zdefiniować „kłopotów”, to mogłoby zawierać białych znaków (spacje, tabulatory, znaki nowej linii, etc.) w tym kraju, co stwarza potrzebę cytowania z "". Jest to jednak nieuniknione, ponieważ dozwolone są spacje, więc ...

Jak prawidłowo używasz lub radzisz sobie ze spacją w nazwie pliku?

W kontekście powłoki / wiersza poleceń zawiń nazwę pliku w pojedyncze lub podwójne cudzysłowy (ale pamiętaj, że nie są to te same inne problemy WRT), lub użyj spacji \, np .:

> foo my\ file\ with\ spaces\ in\ the\ name
Złotowłosa
źródło
1
Jak podasz znak NUL w bash? Chcę to przetestować pod nazwą pliku.
Tim
1
Nie możesz „Wykonaj semantykę” odnosi się do faktu, że w C (i każdym innym języku, który znam) ciągi tekstowe są zakończone zerem. Powłoka jest zaimplementowana w C. Najciekawszą rzeczą, o której mogłem pomyśleć, jest touch $(echo -e "foo\00bar")- -eprzetwarzanie \0Njako wartość ósemkowa, ale gdzieś się gubi, ponieważ to po prostu tworzy plik o nazwie foobar. Oczywiście NULL nie jest drukowalny, ale gwarantuję, że zniknął z powodu ograniczenia ciągu C.
goldilocks
„ciągi tekstowe są zakończone zerem -> Aby wyjaśnić dalej: ciągi są zawsze przechowywane z bajtem zerowym na końcu, dlatego „nie jest to dozwolone” w tekście: Jeśli wstawisz jeden, skutecznie zakończyłeś ciąg w tym momencie. Np. Skończyłby foo[NULL]barjak foow większości zamiarów i celów. Fakt, że tak się nie dzieje, echo -epokazuje, że NULL został gdzieś przycięty.
goldilocks,
5
Zdecydowana większość języków programowania dopuszcza znaki puste w łańcuchach. Zdarza się, że głównym językiem, którym nie jest, jest C, na którym zbudowany jest Unix - i większość powłok uniksowych również nie dopuszcza znaków pustych w łańcuchach. W każdym razie @Tim, wszystkie interfejsy uniksowe używają łańcuchów zakończonych znakiem zerowym, więc bajt zerowy jest jedyną rzeczą, której nigdy nie możesz mieć w nazwie pliku (plus, /który jest separatorem katalogu i nie może być cytowany, więc może znajdować się w nazwie ścieżki ale nie w nazwie pliku).
Gilles „SO- przestań być zły”
1
... ale [nieważne ponownie]. Zresztą i tak nie robiłbym tego zbyt często. Moim zdaniem nie ma powodu, aby znajdowały się w danych tekstowych. Poprawiłbym to, ale to komentarz.
goldilocks
3

Przyczyna jest w dużej mierze historyczna - powrót do mgieł przestrzeni czasowej nie był dozwolony w nazwach plików, więc spacje zostały użyte jako separatory słów kluczowych / nazw plików. Przyszłe interpretery powłok musiały być kompatybilne odwrotnie ze starymi skryptami, dlatego utknęliśmy w bólu głowy, który mamy dzisiaj.

Deweloperzy procesów, które nie muszą zbytnio zajmować się ludźmi, mogą znacznie, znacznie uprościć, całkowicie usuwając spacje. Apple to robi, zawartość / System / Library / CoreServices / zawiera bardzo niewiele spacji, programy ze spacjami są otwierane w imieniu użytkownika, aWouldLookStrangeIfCamelCased. Podobne ścieżki tylko dla Uniksa również unikają spacji.

(nieco pokrewna anegdota: w połowie lat 90. dron Windows powiedział „Wymień jedną rzecz, którą możesz zrobić na komputerze Mac, czego nie mogę zrobić w systemie Windows” -> „Użyj 12 znaków w nazwie pliku”. -> Cisza. Przestrzenie były możliwe również dla tych 12 znaków)

Paweł
źródło
1
Kiedyś korzystałem z V6 Unix (ok. 1978). Spacje były wtedy dozwolone. Jednym z moich zadań było napisanie programu do analizy systemu plików (przy użyciu bezpośredniego dysku we / wy) i poszukiwanie pliku, który ma spacje i spacje w nazwie.
wallyk
czy całkowicie usuwają spacje - czy też nazwy plików zawierają bardzo niewiele spacji?
mikeserv
2

Tak więc, jak wielokrotnie stwierdzono w innym miejscu, nazwa pliku może zawierać prawie dowolny znak. Ale trzeba powiedzieć, że nazwa pliku jest nie plik. Ma on pewną wagę jako atrybut pliku, ponieważ zazwyczaj potrzebujesz nazwy pliku, aby otworzyć plik, ale nazwa pliku wskazuje tylko rzeczywisty plik. Jest to link przechowywany w katalogu, który go nagrał, wraz z numerem i-węzła - co jest znacznie bliższe rzeczywistemu plikowi .

Więc, nazywaj to jak chcesz. Jądro to nie obchodzi - wszystkie obsługiwane przez niego odwołania do plików zajmą się prawdziwymi liczbami i-węzłów. Nazwa pliku jest przeznaczona do spożycia przez ludzi - jeśli chcesz sprawić, że będzie szalona, ​​to twój system plików. Tutaj zrobię trochę szalonych rzeczy:

Najpierw utworzę 20 plików i nadam im nazwy bez spacji, przy czym każda nazwa pliku zawiera o jedną spację więcej niż ostatnia:

until [ $((i=$i+1)) -gt 20 ]
do  v=$v' ' && touch ./"$v"
done

To trochę zabawne. Spójrz na moje ls:

ls -d ./*
./      ./          ./              ./                  ./                 
./      ./          ./              ./                  ./                  
./      ./          ./              ./                  ./                   
./      ./          ./              ./                  ./     

Teraz mam zamiar wykonać kopię lustrzaną tego katalogu:

set -- * ; mkdir ../mirror
ls -i1qdU -- "$@" |
sh -c 'while read inum na
    do  ln -T "$1" ../mirror/$inum
    shift ; done' -- "$@"
ls -d ../mirror/*

Oto ../mirror/zawartość:

../mirror/423759  ../mirror/423764  ../mirror/423769  ../mirror/423774
../mirror/423760  ../mirror/423765  ../mirror/423770  ../mirror/423775
../mirror/423761  ../mirror/423766  ../mirror/423771  ../mirror/423776
../mirror/423762  ../mirror/423767  ../mirror/423772  ../mirror/423777
../mirror/423763  ../mirror/423768  ../mirror/423773  ../mirror/423778

Ok, ale może pytasz - ale co to za dobro? Jak rozpoznać, który jest który? Jak możesz być pewien, że podłączyłeś odpowiedni numer i-węzła do właściwej nazwy pliku?

Dobrze...

echo "heyhey" >>./'    ' 
tgt=$(ls -id ./'    ')
cat ../mirror/${tgt%% .*} \
    $(ls -1td ../mirror/* | head -n1) 

WYDAJNOŚĆ

heyhey
heyhey

Zobacz, zarówno numer ../mirror/"${tgt%% .*}"i- węzła zawarty w, jak i ten, do którego ./' 'odwołuje się, odnoszą się do tego samego pliku. Opisują ten sam plik. Oni to nazywają, ale nic więcej. Nie ma w tym żadnej tajemnicy, tylko pewne niedogodności, które możesz zrobić dla siebie, ale które ostatecznie będą miały niewielki lub żaden wpływ na działanie twojego systemu plików Unix.

mikeserv
źródło