Próbuję zbudować tablicę w bash nazw plików z mojego aparatu:
FILES=(2011-09-04 21.43.02.jpg
2011-09-05 10.23.14.jpg
2011-09-09 12.31.16.jpg
2011-09-11 08.43.12.jpg)
Jak widać, w środku każdej nazwy pliku znajduje się spacja.
Próbowałem zawijać każdą nazwę w cudzysłów i zapisywać spację ukośnikiem odwrotnym, ale żadne z nich nie działa.
Kiedy próbuję uzyskać dostęp do elementów tablicy, nadal traktuje przestrzeń jako elementdelimiter.
Jak prawidłowo przechwycić nazwy plików ze spacją wewnątrz nazwy?
FILES[0] = ...
? (Edycja: właśnie zrobiłem; nie działa. Ciekawe).find . -maxdepth 1 -type f -iname \*.$1 -printf '%f\n'
); dla elementu w $ {tablica [@]}; do echo $ element; gotoweOdpowiedzi:
Myślę, że problem może częściowo dotyczyć sposobu uzyskiwania dostępu do elementów. Jeśli zrobię coś prostego
for elem in $FILES
, mam ten sam problem co ty. Jeśli jednak uzyskam dostęp do tablicy za pośrednictwem jej indeksów, tak jak to, zadziała, jeśli dodam elementy numerycznie lub ze znakami ucieczki:Każda z tych deklaracji
$FILES
powinna działać:lub
lub
źródło
echo "${FILES[$i]}"
.). Nie ma to znaczeniaecho
, ale będzie miało znaczenie dla wszystkiego, co używa go jako nazwy pliku.for f in "${FILES[@]}"
.#
) symbol zrobić wfor ((i = 0; i < ${#FILES[@]}; i++))
rachunku?Coś musi być nie tak ze sposobem uzyskiwania dostępu do elementów tablicy. Oto jak to się robi:
Ze strony podręcznika bash :
Oczywiście podczas uzyskiwania dostępu do pojedynczego członka należy również używać podwójnych cudzysłowów
źródło
expands to a single word with the value of each array member separated by the first character of the IFS special variable
for elem in "${files[@]}"
podczas gdy oni mająfor elem in ${files[@]}
- więc spacje mylą ekspansję i próby uruchomienia poszczególnych słów.Musisz użyć IFS, aby zatrzymać spację jako ogranicznik elementu.
Jeśli chcesz się rozdzielić na podstawie. następnie po prostu wykonaj IFS = "." Mam nadzieję, że ci to pomoże :)
źródło
IFS=""
przed konstrukcją tablicy .Zgadzam się z innymi, że prawdopodobnie sposób uzyskiwania dostępu do elementów jest problemem. Cytowanie nazw plików w przypisaniu tablicy jest poprawne:
Użycie podwójnych cudzysłowów wokół dowolnej tablicy formularza
"${FILES[@]}"
powoduje podzielenie tablicy na jedno słowo na element tablicy. Poza tym nie rozdziela słów.Używanie
"${FILES[*]}"
również ma specjalne znaczenie, ale łączy elementy tablicy z pierwszym znakiem $ IFS, w wyniku czego powstaje jedno słowo, które prawdopodobnie nie jest tym, czego chcesz.Użycie gołego
${array[@]}
lub${array[*]}
poddaje wynik tej ekspansji dalszemu dzieleniu na słowa, więc skończysz na słowach podzielonych na spacje (i wszystko inne$IFS
) zamiast jednego słowa na element tablicy.Używanie pętli for w stylu C jest również w porządku i pozwala uniknąć martwienia się o dzielenie słów, jeśli nie masz co do tego jasności:
źródło
Ucieczka działa.
Wynik:
Cytowanie ciągów również daje taki sam wynik.
źródło
Gdybyś miał taką tablicę: #! / Bin / bash
Otrzymasz:
Nie wiem dlaczego, ale pętla rozbija spacje i umieszcza je jako osobny element, nawet jeśli otoczysz go cudzysłowami.
Aby obejść ten problem, zamiast wywoływać elementy tablicy, wywołujesz indeksy, które pobierają pełny ciąg zawinięty w cudzysłów. Musi być zawarty w cudzysłowie!
Wtedy otrzymasz:
źródło
Nie jest to dokładna odpowiedź na problem cytowania / ucieczki z pierwotnego pytania, ale prawdopodobnie coś, co faktycznie byłoby bardziej przydatne dla operacji:
Tam, gdzie, oczywiście, wyrażenie musiałoby być dostosowane do konkretnego wymagania (np.
*.jpg
Dla wszystkich lub2001-09-11*.jpg
tylko dla zdjęć z określonego dnia).źródło
Innym rozwiązaniem jest użycie pętli „while” zamiast pętli „for”:
źródło
Jeśli nie utkniesz w używaniu
bash
, różne sposoby obsługi spacji w nazwach plików są jedną z zalet skorupy ryby . Rozważmy katalog zawierający dwa pliki: „a b.txt” i „b c.txt”. Oto rozsądne przypuszczenie, jak przetworzyć listę plików wygenerowanych przez inne poleceniebash
, ale kończy się to niepowodzeniem z powodu spacji w nazwach plików, które napotkałeś:W
fish
przypadku składnia jest prawie identyczna, ale wynik jest taki, jakiego można się spodziewać:Działa inaczej, ponieważ fish dzieli wyjście poleceń na znaki nowej linii, a nie spacje.
Jeśli masz przypadek, w którym chcesz podzielić na spacje zamiast nowych linii,
fish
ma do tego bardzo czytelną składnię:źródło
Kiedyś resetowałem wartość IFS i wycofywanie po zakończeniu .
Możliwe wyjście z pętli:
źródło