Получить один элемент строки пути, используя bash

9

У меня есть файл ASCII, содержащий пути к файлам, которые я прочитал, запустив:

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

Файл содержит пути к файлам со следующим шаблоном:

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

Как я могу получить определенную часть строки пути (от /до /), например, мне нужно получить вывод, который печатает:

first
second
third

а также

example1
example1
example2

Я уверен, что есть способ сделать это, используя регулярные выражения и sed, но я не знаком с этим.

mcExchange
источник

Ответы:

17

Используйте 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/Устанавливает разделитель столбцов для /и -f2выбирают 2 - й столбец.

Конечно, вы также можете использовать переменные Bash вместо имени файла или данных канала в cutкоманду:

cut -d/ -f3 $MyVariable
echo ./another/example/path | cut -d/ -f3
Byte Commander
источник
Использование | cut -d/ -f3 в трубе сделало свое дело. Спасибо! Теперь это полная команда: while read p; do echo $p; done < filelist.txt | cut -d/ -f3
mcExchange
3
@mcExchange Нет причин использовать этот цикл while. Это гораздо проще сделать cut -d/ -f3 filelist.txt
Монти Хардер
1
Кроме того, избегание while позволяет избежать проблем с цитированием и не приведет к сбою в новых строках имен файлов.
Фолькер Сигел
10

Вы можете сделать это прямо в вашей readкоманде, используя IFSпеременную, например

$ while IFS=/ read -r p1 p2 p3 r; do echo "$p2"; done < filelist.txt 
first
second
third
steeldriver
источник
5

Ты можешь использовать 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
источник
3

Если нам нужен какой-либо элемент пути, лучше всего использовать что-то, что может разбить строку на поля, такие как , ,, или , Однако, также может выполнять работу с подстановкой параметров, используя замену шаблона и выбрасывая все в массив.

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

Теперь у нас есть массив предметов, сделанных из пути. Обратите внимание, что если путь содержит пробелы, он может включать изменение внутреннего разделителя полей IFS.

Сергей Колодяжный
источник
1

Bash и cutпуть, однако альтернатива с использованием Perl:

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

для второго /неограниченного поля и

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

за третье- /неограниченное поле.

  • -l: включает автоматическую обработку конца строки. У него есть два отдельных эффекта. Во-первых, он автоматически разбивает $ / (разделитель входных записей) при использовании с -n или -p. Во-вторых, он присваивает $ \ (разделителю выходной записи) значение octnum, чтобы в любом операторе печати этот разделитель был добавлен обратно. Если октнум опущен, устанавливает $ \ текущее значение $ /.
  • -a: включает режим автоматического разделения при использовании с -n или -p. Неявная команда split для массива @F выполняется в первую очередь в неявном цикле while, создаваемого -n или -p.
  • -n: заставляет Perl принять следующий цикл вокруг вашей программы, который заставляет его перебирать аргументы имени файла, вроде sed -n или awk:

    LINE:
      while (<>) {
          ...             # your program goes here
      }
  • -e: может использоваться для ввода одной строки программы;

  • print(@F[N]): печатает N-ное поле.
% 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
кос
источник