Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have a directory full of files ending with different extensions, how would I list/select only the files ending with .in and corresponding .out that share the same basename?

e.g.

file1.txt
file1.in
file2.in
file3.in
file2.out
file3.out

What I want to select from these files are:

file2.in
file2.out
file3.in
file3.out
share|improve this question

4 Answers 4

Since you want .in to be paired with .out, loop through only *.in and check if there is a corresponding .out file, if so, print out both:

for f in *.in; do
  if [[ -f ${f%.in}.out ]]; then
    echo $f
    echo ${f%.in}.out
  fi
done
share|improve this answer
    
This is how I would have done it. Sweet and simple. I'd simplify it to one line though: for f in *.in; do [[ -e ${f%.in}.out ]] && echo $f ${f%.in}.out; done –  ryran Nov 26 '12 at 15:03

First match against all files, and check if .out file exists, then print the name:

for x in *; do
   if [[ "$x" =~ ^(.*)\.in ]] && [[ -f ${BASH_REMATCH[1]}.out ]];then 
      echo -n "$x ${x%%.in}.out "; 
   fi
done
echo
share|improve this answer
    
Daaaayumn. I had no idea BASH could save substrings to a variable like that. That BASH_REMATCH array is awesome. Niiice! PS: You could simplify that into one [[ ... && ... ]] expression. –  ryran Nov 26 '12 at 3:44
    
@ryran, [[ ... ]] & [[ ... ]] is guaranteed to be processed left-to-right. Are you sure that [[ ... && ... ]] is also so guaranteed? (Not so interesting if it merely happens now to be so processed in the current version of bash.) –  dubiousjim Nov 26 '12 at 9:53
    
@dubiousjim: Yes, I'm sure that [[ ... && ...]] is processed as expected. Take a look at the bash man page under the [[ expression ]] section. –  ryran Nov 26 '12 at 14:58
    
Wouldn't it be more efficient to only select the "*.in" files, e.g. "for x in *.in; do" rather than selecting all files and then checking if the file ends with ".in"? –  KayakJim Nov 26 '12 at 15:00

You can list all those files, remove the extensions, filter duplicates and print them:

$ ls | grep '\(\.in\|.out\)$' | sed 's/....$//' \
     | sort | uniq -c | grep '^[\t ]*2' | sed 's/^[\t ]\+2 //'

Advantages:

  • does not need bash
  • does just one expensive operation - directory listing - i.e. does not need to stat(2) each file (as in [[ -f ... ]])

In case the ls already alphabetically sorts its output the sort command can be removed from the pipe. I don't know if POSIX specifies the sorting behavior of a ls.

The pipe prints all the basenames if files with .in and .out extension.

If you then need a list of the corresponding files you have to suffix the list with the previously filtered extensions. For example like this:

$ ls | grep '\(\.in\|.out\)$' | sed 's/....$//' \
     | sort | uniq -c | grep '^[\t ]*2' \
     | sed -e 's/^[\t ]\+2 //' -e 's/$/.in/ ; p; s/in$/out/'
share|improve this answer

With zsh:

has_out() [[ -e $REPLY:r.out ]]
ls -ld -- *.in(+has_out)
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.