1

To start with, I know this way is quite not the right one, as often mentioned why shouldn't I parse the output of ls, but it is a part of my university project (so I could use sed and awk along).

I have to find files which names start with a given string. I stared with listing the current directory using ls:

ls -LR1

which gives me the example output:

.:
bin
etc
games
include
lib
man
sbin
share
src

./bin:
apt
gnome-help
highlight
mint-sha256sum
pastebin
search
szukaj
yelp

./etc:

./games:

./include:

./lib:
python2.7
python3.5

./lib/python2.7:
dist-packages
site-packages

./lib/python2.7/dist-packages:

./lib/python2.7/site-packages:

./lib/python3.5:
dist-packages

./lib/python3.5/dist-packages:

./man:

./sbin:

./share:
ca-certificates
emacs
fonts
man
sgml
xml

./share/ca-certificates:

./share/emacs:
site-lisp

./share/emacs/site-lisp:

./share/fonts:

./share/man:

./share/sgml:
declaration
dtd
entities
misc
stylesheet

./share/sgml/declaration:

./share/sgml/dtd:

./share/sgml/entities:

./share/sgml/misc:

./share/sgml/stylesheet:

./share/xml:
declaration
entities
misc
schema

./share/xml/declaration:

./share/xml/entities:

./share/xml/misc:

./share/xml/schema:

./src:

Now I want to use sed or possibly awk to get to get files with names starting with given string, lets say 'Do'. I would like to achieve something like this:

  1. sed (or awk?) parses each line and searches for line that starts with 'Do'
  2. If there is a match, moves to previous line and searches for . (which is an indicator for relative path), if there's no match jumps to the line before and so on
  3. Prints the line as relative path:.path/filename

Is it even possible to achive? Thank you for your help!

  • 1
    find . -name 'Do*' – Wildcard Oct 14 '16 at 20:03
  • Thank you for your answer. I am aware of find existence, however as stated in OP, I am required to use sed and/or awk. – Dandry Oct 14 '16 at 20:09
  • 3
    Show your teacher "The Evolution of a Programmer." Then tell your teacher to come up with some better example use cases for text processing; there are literally thousands of cases where sed or awk are the correct tools for the job. Finding files isn't one of them. – Wildcard Oct 14 '16 at 20:14
2

As an example, let's consider these files:

$ ls -LR1
.:
a

./a:
b

./a/b:
bad
Do_good

Now, let's find the file that you want:

$ ls -LR1 | awk '/^\.\//{sub(/:$/, "/", $0); dir=$0} /^Do/{print dir $0}'
./a/b/Do_good

How it works:

  • /^\.\//{sub(/:$/, "/", $0); dir=$0}

    Every time that we find a line that begins with ./, we replace the find : with a / and update the variable dir

  • /^Do/{print dir $0}

    Every time that we find a line that begins Do, we print the variable dir followed by this line.

Limitation: As you are aware, the output of ls is intended to be human-readable and parsing it is unreliable. This code is only for purposes of demonstrating the use of awk. It should not be used for anything serious.

Preferred method -- 1

As wildcard pointed out, find is the right tool for this task:

$ find . -name 'Do*'
./a/b/Do_good

Preferred method -- 2 (requires bash)

In bash, as Kusalananda points out, one can recursively search for files using the globstar feature:

shopt -s globstar nullglob
printf '%s\n' **/Do*
  • Or printf '%s\n' **/Do* in shells that supports **. – Kusalananda May 28 at 10:02
  • @Kusalananda Yes, very good. Thank you. A globstar solution has been added to the answer. – John1024 May 29 at 6:04
2

With sed, you'd use the hold space to store the path of the last seen directory:

sed -n '
  /^\..*:$/{
    h;d
  }
  /^Do/{
    G
    s|\(.*\)\n\(.*\):|\2/\1|p
  }'
  • Thank you for the solution which uses sed! – Dandry Oct 18 '16 at 12:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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