Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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.

share|improve this question
up vote 15 down vote accepted

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
share|improve this answer
    
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 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 – Monty Harder Mar 24 at 14:30
1  
Also, avoiding the while avoids quoting problems, and will not fail with newlines in file names. – Volker Siegel Mar 24 at 20:36

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
share|improve this answer

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
share|improve this answer

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 .

share|improve this answer

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
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.