Jak wybrać pole / kolumnę z wyjścia `ls -l`?

22

Mój cel jest zwodniczo prosty (przynajmniej dla mnie). Chcę wziąć wynik ls -llub ls -lhi wybrać tylko jedno pole.

Chcę, aby było to jak najbardziej kuloodporne, co oznacza, załóżmy, że nazwy plików mogą mieć zmienną liczbę spacji, nie wszystko w polu ma taką samą długość itp.

Punkty bonusowe za posiadanie skryptu, który pobierze nazwę pola (lub nawet tylko numer pola), a następnie zwróci zawartość pola.

Chcę się odwrócić

wprowadź opis zdjęcia tutaj

w:

wprowadź opis zdjęcia tutaj

soandos
źródło

Odpowiedzi:

41

Spróbować ls -l | awk '{print $7}'.

awk wybiera kolumny, więc idealnie nadaje się do tego zadania.

Corey Whitaker
źródło
3
Jak wyjaśniono przez @ormaaj: Nie polegaj na tym, że informacje są dostępne w określonych miejscach za pomocą ls. findPolecenia jest ogromnie pomocne.
Paddy Landau
@PaddyLandau Jak użyć polecenia find do wydrukowania rozmiaru pliku w megabajtach, tak jak mogę ls -l --block-size=M?
SurpriseDog
@Benjamin - lsKomenda nie jest standardem POSIX, więc skrypt zależny od lsmoże się zepsuć na różnych systemach, a nawet z czasem. Zobacz odpowiedź @ormaaj na tej stronie, aby uzyskać więcej informacji. Jednym ze sposobów zrobienia tego, o co prosisz, jest pętla Bash. Oto przykład. for FILENAME in *; do FILESIZE=$(( $( stat --format=%s "${FILENAME}" ) / 1024 )); echo "${FILENAME}" ${FILESIZE}; done. Oczywiście zamiast tego echoużyłbyś swojego przetwarzania.
Paddy Landau
@PaddyLandau Właśnie skończyłem przesyłać dane wyjściowe polecenia find, do ... | xargs -d '\n' du -mktórego działa równie dobrze.
SurpriseDog
@Benjamin Możesz przyjrzeć się -execopcji find.
Paddy Landau
17

Nigdy nie analizuj ls . Użyj GNU find. Lub jeśli przenośność nie jest ważne stat(1).

find . -maxdepth 1 -printf '%Td\n'

Aby odczytać dane inne niż listy nazw plików linia po linii i podzielić na pola, patrz: BashFAQ / 001

Nie ma metod, aby wiarygodnie odczytać listę nazw plików rozdzielaną znakiem nowej linii, która ma sens w większości przypadków.

ormaaj
źródło
1

Możesz pobrać konkretną kolumnę w powłoce, taką jak:

ls -al | while read perm bsize user group size month day time file; do echo $day; done

lub awkjak pokazano w odpowiedzi @Corey , cut -c44-45działałby również po dostosowaniu (ponieważ lsma ustalone kolumny) lub cokolwiek innego, jednak głównym problemem jest to, że nie będzie niezawodny i kuloodporny (np. w Uniksie może być $6, nie $7, i zmienia się w zależności od argumentów), co powoduje, że nie jest przyjazny dla maszyny, dlatego w ogóle nie zaleca się analizowania lspoleceń .

Najlepiej jest użyć różnych dostępnych poleceń, takich jak findlub stat, które mogą zapewnić odpowiednie opcje formatowania danych wyjściowych według potrzeb. Na przykład:

$ stat -c "%x %n" *
2016-04-10 04:53:07.000000000 +0100 001.txt
2016-04-10 05:08:42.000000000 +0100 7c1c.txt

Aby zwrócić kolumnę zawierającą tylko dni modyfikacji, spróbuj tego przykładu:

stat -c "%x" * | while read ymd; do date --date="$ymd" "+%d"; done

Warto zauważyć, że GNU statmoże mieć inne opcje niż BSD stat, więc nadal nie będzie kuloodporny w różnych systemach operacyjnych.

kenorb
źródło
1
+1 za wzmiankę, że ls nie powinien być analizowany tak samo, jak do użycia stat. datejednak jest niepoprawnie skonfigurowany. Powinieneś dodać --date=$ymd, ponieważ datesam wydrukuje bieżący dzień, ale tutaj celem jest konwersja formatu daty pliku
Sergiy Kolodyazhnyy 10.04.2016
ls -la | cut -c32-33Komenda w całkowitej uczciwości jest po prostu całkowicie niewiarygodne, nie tylko z powodu możliwych pułapek z nazwami, ale po prostu dlatego, że to zależy od długości i pliki nazwy użytkownika wielkości. stat -c "%x" *.*Komenda wygląda ok, ale stosując *.*jesteś restricing go tylko do nazw plików zawierających kropkę. Wydaje mi się, że celem było złapanie również ukrytych plików; w takim przypadku należy włączyć globbing dla dotfiles wcześniej i użyć *zamiast *.*: shopt -s dotglob; stat -c "%x" * | [...].
Kos
Ach, a także to, co powiedział Serg, powinieneś dodać --date="$ymd"do datepolecenia, w przeciwnym razie wydrukuje bieżący dzień miesiąca.
Kos
Dziękuję za komentarze. Rozwiązałem problemy i podałem lepszy wstępny przykład.
kenorb