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.
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 laterecho"${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 )); thenecho"No subdirectories found" >&2
fi
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.
Odpowiedzi:
To byłoby to
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.
źródło
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.declare -a ARR; ARR+=('$(ls -d "$INPUT_DIR"/*)')
tylko zwraca$(ls -d $INPUT_DIR/*)
ARR+=("$(ls -d */)")
powinno działać. Jeśli nie, daj mi znać.O ile to możliwe, należy unikać analizowania wyników
ls
(zobacz temat wiki Grega ). Zasadniczo wynikls
będzie niejednoznaczny, jeśli w którejkolwiek nazwie pliku znajdują się zabawne znaki. Zwykle jest to też strata czasu. W tym przypadku, kiedy wykonujeszls -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 dols -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).ls
Polecenie 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ędziels
szukał 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 dols
. 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
źródło
/
w nazwie katalogu?ls
to 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 przeanalizowanials
danych wyjściowych.ls
robią 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ściowels -d */
, otrzymasz dokładnie to samo, z czego otrzymasz bezpośrednio*/
(z wyjątkiem sytuacji, gdy nie ma dopasowań, a to łatwo sprawdzić).A lazy sysadmin is a good sysadmin.
być może moje własnels
parsowanie 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.Spowoduje to wydrukowanie plików w tych katalogach wiersz po wierszu.
array=(ww/* ee/* qq/*) printf "%s\n" "${array[@]}"
źródło