13

I have an ASCII file containing filepaths which I read by running:

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

The file contains filepaths with the following pattern:

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

How can I get a specific part of the path string (from / to / ), e.g. I need to get an output that prints:

first
second
third

and also

example1
example1
example2

I'm sure there is a way of doing this using regular expressions and sed, but I'm not familiar with it.

5 Answers 5

23

Use 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/ sets the column delimiter to / and the -f2 selects the 2nd column.

You can of course also use Bash variables instead of a file name or pipe data into the cut command:

cut -d/ -f3 $MyVariable
echo ./another/example/path | cut -d/ -f3
3
  • 1
    Using | cut -d/ -f3 in a pipe did the trick. Thanks! This is the full command now: while read p; do echo $p; done < filelist.txt | cut -d/ -f3
    – mcExchange
    Mar 24, 2016 at 12:16
  • 3
    @mcExchange There's no reason to use that while loop. It's far simpler to just do cut -d/ -f3 filelist.txt Mar 24, 2016 at 14:30
  • 1
    Also, avoiding the while avoids quoting problems, and will not fail with newlines in file names. Mar 24, 2016 at 20:36
10

You could do it directly in your read command, using the IFS variable e.g.

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

You can use 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
4

If we want any element of the path, it is best to use something that can break up a string into fields, such as , ,, or . However, can also do the job with parameter substitution,using pattern replacement and throwing everything into an 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

Now we have an array of items made out of the path. Note that if the path contains spaces, it may involve altering internal field separator IFS .

0
1

Bash and cut are the way to go, however an alternative using Perl:

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

for the second /-delimited field and

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

for the third /-delimited field.

  • -l: enables automatic line-ending processing. It has two separate effects. First, it automatically chomps $/ (the input record separator) when used with -n or -p. Second, it assigns $\ (the output record separator) to have the value of octnum so that any print statements will have that separator added back on. If octnum is omitted, sets $\ to the current value of $/.
  • -a: turns on autosplit mode when used with a -n or -p. An implicit split command to the @F array is done as the first thing inside the implicit while loop produced by the -n or -p.
  • -n: causes Perl to assume the following loop around your program, which makes it iterate over filename arguments somewhat like sed -n or awk:

    LINE:
      while (<>) {
          ...             # your program goes here
      }
    
  • -e: may be used to enter one line of program;

  • print(@F[N]): prints the Nth field.
% 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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .