Jak przypisać ls do tablicy w Linux Bash?


Odpowiedzi:


111

To byłoby to

array=($(ls -d */))

EDYTUJ: Zobacz rozwiązanie Gordona Davissona, aby uzyskać bardziej ogólną odpowiedź (np. Jeśli twoje nazwy plików zawierają znaki specjalne). Ta odpowiedź jest jedynie poprawką składni.


14
Nie będzie to działać poprawnie, jeśli nazwy katalogów zawierają spacje.
chepner

1
Aby rozwiązać problem spacji lub znaków specjalnych, najpierw zadeklaruj tablicę bez żadnych wartości, a następnie użyj wbudowanej ARR+=('$(ls -d */)')do edycji elementów w tablicy, używając pojedynczych cudzysłowów, aby poradzić sobie ze znakami specjalnymi, aby dodać lub usunąć elementy do niej szyk. Pojedyncze cudzysłowy zachowują znaki literału i eliminują potrzebę używania znaków specjalnych, aby zajmować się nimi w nazwach katalogów.
Yokai,

@Yokai Twoja sugestia brzmi wspaniale, ale nie zadziałała dla mnie na Ubuntu 16.04 lub MacOs. Bash rozszerza kod między pojedynczymi cudzysłowami w następujący sposób: declare -a ARR; ARR+=('$(ls -d "$INPUT_DIR"/*)')tylko zwraca$(ls -d $INPUT_DIR/*)
Agile Bean

1
Mój błąd. Powinien to być cudzysłów, aby można było rozwinąć podstawianie poleceń. ARR+=("$(ls -d */)")powinno działać. Jeśli nie, daj mi znać.
Yokai,

2
@Yokai, który dodaje tylko jeden element łącznie (z kilkoma znakami nowej linii), a nie jeden element na katalog.
Charles Duffy

79

O ile to możliwe, należy unikać analizowania wyników ls(zobacz temat wiki Grega ). Zasadniczo wynik lsbędzie niejednoznaczny, jeśli w którejkolwiek nazwie pliku znajdują się zabawne znaki. Zwykle jest to też strata czasu. W tym przypadku, kiedy wykonujesz ls -d */, dzieje się tak, że powłoka rozwija się */do listy podkatalogów (która jest dokładnie tym, czego chcesz), przekazuje tę listę jako argumenty do ls -d, który patrzy na każdy z nich, mówi "tak, to jest katalog w porządku ”i drukuje go (w niespójnym, a czasem niejednoznacznym formacie). lsPolecenie nie robi nic użytecznego!

Cóż, ok, robi jedną rzecz, która jest przydatna: jeśli nie ma podkatalogów, */zostanie pozostawiony bez zmian, będzie lsszukał podkatalogu o nazwie "*", nie będzie go znajdował, wypisze komunikat o błędzie, że nie istnieje (aby stderr) i nie wypisuje "* /" (na standardowe wyjście).

Prostszym sposobem na utworzenie tablicy nazw podkatalogów jest użycie funkcji glob ( */) bez przekazywania jej do ls. Ale aby uniknąć umieszczania "* /" w tablicy, jeśli nie ma żadnych podkatalogów, powinieneś najpierw ustawić nullglob (ponownie, zobacz wiki Grega ):

shopt -s nullglob
array=(*/)
shopt -u nullglob # Turn off nullglob to make sure it doesn't interfere with anything later
echo "${array[@]}"  # Note double-quotes to avoid extra parsing of funny characters in filenames

Jeśli chcesz wydrukować komunikat o błędzie, jeśli nie ma podkatalogów, lepiej zrób to sam:

if (( ${#array[@]} == 0 )); then
    echo "No subdirectories found" >&2
fi

2
Dziękuję za komentarz, mimo że nie został oznaczony jako odpowiedź, był dość pouczający i doceniam to.
Jake H

A co, jeśli nie chcesz tego /w nazwie katalogu?
shinzou

Problemy / kwestie przedstawione na wiki grega nie są rzeczami, które nie mogą być łatwo rozwiązane za pomocą zwykłych konstrukcji warunkowych. lsto proste polecenie. Jego wyjście to stringi. Bash jest zbyt dobry w analizowaniu ciągów. Właściwe wyrażenie regularne to wszystko, co jest potrzebne do bezpiecznego przeanalizowania lsdanych wyjściowych.
Yokai

@Yokai Różne wersje lsrobią różne rzeczy z zabawnymi / niedrukowalnymi znakami w nazwach plików, więc nie ma spójnego sposobu na przeanalizowanie wyników w postaci listy nazw plików. I jak powiedziałem, w rzeczywistości nie robi nic użytecznego: jeśli poprawnie przeanalizujesz dane wyjściowe ls -d */, otrzymasz dokładnie to samo, z czego otrzymasz bezpośrednio */(z wyjątkiem sytuacji, gdy nie ma dopasowań, a to łatwo sprawdzić).
Gordon Davisson

Podsumowując: A lazy sysadmin is a good sysadmin.być może moje własne lsparsowanie jest specyficzne dla wersji, którą mam, lub do której jestem przyzwyczajony, ale jak dotąd nie mieli żadnych problemów z dystrybucjami Linuksa, na których je testowałem. Mogę mówić tylko z doświadczenia.
Yokai

8

Spowoduje to wydrukowanie plików w tych katalogach wiersz po wierszu.

array=(ww/* ee/* qq/*)
printf "%s\n" "${array[@]}"
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.