Uzyskaj jeden element ciągu ścieżki za pomocą bash

9

Mam plik ASCII zawierający ścieżki plików, które czytam, uruchamiając:

while read p; do echo $p; done < filelist.txt

Plik zawiera ścieżki plików o następującym wzorze:

./first/example1/path
./second/example1/path
./third/example2/path

Jak mogę uzyskać określoną część ciągu ścieżki (od /do /), np. Muszę uzyskać wynik, który wyświetla:

first
second
third

i również

example1
example1
example2

Jestem pewien, że można to zrobić za pomocą wyrażeń regularnych sed, ale nie jestem z tym zaznajomiony.

mcExchange
źródło

Odpowiedzi:

17

Użyj cut:

$ cat filelist.txt
./first/example1/path
./second/example1/path
./third/example2/path

$ cut -d/ -f2 filelist.txt 
first
second
third

$ cut -d/ -f3 filelist.txt 
example1
example1
example2

-d/Przedstawia separator do kolumny /i -f2wybiera 2. kolumny.

Oczywiście możesz również użyć zmiennych Bash zamiast nazwy pliku lub danych potoku do cutpolecenia:

cut -d/ -f3 $MyVariable
echo ./another/example/path | cut -d/ -f3
Bajt Dowódca
źródło
Użycie | cut -d/ -f3 w fajce załatwiło sprawę. Dzięki! To jest teraz pełne polecenie: while read p; do echo $p; done < filelist.txt | cut -d/ -f3
mcExchange
3
@mcExchange Nie ma powodu, aby używać tej pętli while. Jest to o wiele prostsze cut -d/ -f3 filelist.txt
Monty Harder
1
Ponadto unikanie while pozwala uniknąć problemów z cytowaniem i nie zawiedzie z nowymi liniami w nazwach plików.
Volker Siegel
10

Możesz to zrobić bezpośrednio w swoim readpoleceniu, używając IFSzmiennej np

$ while IFS=/ read -r p1 p2 p3 r; do echo "$p2"; done < filelist.txt 
first
second
third
steeldriver
źródło
5

Możesz użyć awk

pilot6@Pilot6:~$ cat filelist.txt
./first/example1/path
./second/example1/path
./third/example2/path

pilot6@Pilot6:~$ awk -F "/" '{print $2}' filelist.txt
first
second
third

pilot6@Pilot6:~$ awk -F "/" '{print $3}' filelist.txt
example1
example1
example2
Pilot 6
źródło
3

Jeśli chcemy dowolnego elementu ścieżki, najlepiej użyć czegoś, co może rozbić ciąg na pola, takie jak , ,lub . Jednak, może również wykonać zadanie z podstawieniem parametrów, używając zamiany wzorców i wrzucając wszystko do tablicy.

$> echo ${FILE//\//\ }                                                         
sys class backlight intel_backlight brightness
$> ARRAY=( ${FILE//\//" " } )                                                  
$> echo ${ARRAY[2]}
backlight

$> FILE="./dir1/dir2/file.txt"                                                 
$> ARRAY=( ${FILE//\/" "} )
$> echo ${ARRAY[@]}                                                            
. dir1 dir2 file.txt
$> echo ${ARRAY[1]}
dir1

Teraz mamy szereg przedmiotów wykonanych ze ścieżki. Zauważ, że jeśli ścieżka zawiera spacje, może to wymagać zmiany wewnętrznego separatora pól IFS.

Sergiy Kolodyazhnyy
źródło
1

Bash i cutsą dobrą drogą, jednak alternatywą jest użycie Perla:

perl -F/ -lane 'print(@F[1])' filelist.txt

dla drugiego /ograniczonego pola i

perl -F/ -lane 'print(@F[2])' filelist.txt

dla trzeciego /ograniczonego pola.

  • -l: umożliwia automatyczne przetwarzanie końca linii. Ma dwa osobne efekty. Po pierwsze, automatycznie używa komendy $ / (separator rekordów wejściowych), gdy jest używana z -n lub -p. Po drugie, przypisuje $ \ (separator rekordu wyjściowego), aby miał wartość octnum, dzięki czemu wszelkie instrukcje drukowania będą miały ponownie dodany separator. Jeśli octnum zostanie pominięty, ustawia $ \ na bieżącą wartość $ /.
  • -a: włącza tryb automatycznego podziału, gdy jest używany z -n lub -p. Ujawnione polecenie podziału na tablicę @F jest wykonywane jako pierwsza rzecz w niejawnej pętli while generowanej przez -n lub -p.
  • -n: powoduje, że Perl zakłada następującą pętlę wokół twojego programu, co powoduje iterację argumentów nazw plików, takich jak sed -n lub awk:

    LINE:
      while (<>) {
          ...             # your program goes here
      }
  • -e: może być użyty do wprowadzenia jednego wiersza programu;

  • print(@F[N]): drukuje n-te pole.
% cat filelist.txt 
./first/example1/path
./second/example1/path
./third/example2/path
% perl -F/ -lane 'print(@F[1])' filelist.txt
first
second
third
% perl -F/ -lane 'print(@F[2])' filelist.txt
example1
example1
example2
kos
źródło