Dapatkan satu elemen string jalur menggunakan bash

9

Saya memiliki file ASCII yang berisi filepath yang saya baca dengan menjalankan:

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

File tersebut berisi filepath dengan pola berikut:

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

Bagaimana saya bisa mendapatkan bagian tertentu dari string path (dari /ke /), misalnya saya perlu mendapatkan output yang dicetak:

first
second
third

dan juga

example1
example1
example2

Saya yakin ada cara untuk melakukan ini menggunakan ekspresi reguler dan sed, tapi saya tidak terbiasa dengannya.

mcExchange
sumber

Jawaban:

17

Gunakan 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

The -d/menetapkan kolom pembatas untuk /dan -f2menyeleksi 2 kolom.

Tentu saja Anda juga dapat menggunakan variabel Bash alih-alih nama file atau data pipa ke cutperintah:

cut -d/ -f3 $MyVariable
echo ./another/example/path | cut -d/ -f3
Komandan Byte
sumber
Menggunakan | cut -d/ -f3 pipa melakukan trik. Terima kasih! Ini adalah perintah lengkap sekarang: while read p; do echo $p; done < filelist.txt | cut -d/ -f3
mcExchange
3
@ mcExchange Tidak ada alasan untuk menggunakannya saat loop. Jauh lebih sederhana untuk dilakukan cut -d/ -f3 filelist.txt
Monty Harder
1
Juga, menghindari sementara menghindari mengutip masalah, dan tidak akan gagal dengan baris baru dalam nama file.
Volker Siegel
10

Anda bisa melakukannya langsung di readperintah Anda , menggunakan IFSvariabel mis

$ while IFS=/ read -r p1 p2 p3 r; do echo "$p2"; done < filelist.txt 
first
second
third
Steeldriver
sumber
5

Kamu bisa menggunakan 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
Pilot6
sumber
3

Jika kita menginginkan elemen jalan apa pun, yang terbaik adalah menggunakan sesuatu yang dapat memecah string menjadi bidang, seperti , ,, atau . Namun, juga dapat melakukan pekerjaan dengan substitusi parameter, menggunakan penggantian pola dan membuang semuanya ke dalam array.

$> 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

Sekarang kami memiliki berbagai item yang dibuat dari jalur. Perhatikan bahwa jika jalur berisi spasi, mungkin melibatkan mengubah pemisah bidang internal IFS.

Sergiy Kolodyazhnyy
sumber
1

Bash dan cutadalah cara untuk pergi, namun alternatif menggunakan Perl:

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

untuk bidang kedua yang /direvisi dan

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

untuk bidang ketiga yang /direvisi.

  • -l: mengaktifkan pemrosesan akhir baris otomatis. Ini memiliki dua efek terpisah. Pertama, secara otomatis chomps $ / (pemisah rekaman input) saat digunakan dengan -n atau -p. Kedua, ia menetapkan $ \ (pemisah catatan output) untuk memiliki nilai octnum sehingga setiap pernyataan cetak akan memiliki pemisah yang ditambahkan kembali. Jika octnum dihilangkan, tetapkan $ \ ke nilai saat ini $ /.
  • -a: mengaktifkan mode autosplit saat digunakan dengan -n atau -p. Perintah split implisit ke array @F dilakukan sebagai hal pertama di dalam loop implisit saat diproduksi oleh -n atau -p.
  • -n: menyebabkan Perl untuk mengasumsikan loop berikut di sekitar program Anda, yang membuatnya iterate atas argumen nama file agak seperti sed -n atau awk:

    LINE:
      while (<>) {
          ...             # your program goes here
      }
  • -e: dapat digunakan untuk memasukkan satu baris program;

  • print(@F[N]): mencetak bidang Nth.
% 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
sumber