If I had a string like 45mb ./aaaa/bbbb/cccc/dddd and I use a regex like [^\/]*\/ it will match 45mb ./aaaa/bbbb/cccc/

I only want it to match ./aaaa/bbbb/cccc/ but I can't figure out how to do it.

I want to specifically match/find all occurrences of "everything before a forward slash up to and including the slash" as I want to use sed to substitute the matches like in the below sed command but not losing the file size bit at the start.

sed -e 's/[^\/]*\//--/g

Hopefully that makes some sense. I tried look ahead/behinds but I don't know if that's the correct regex solution for this.

  • Is the format always filesize {space} filename? Maybe awk would suffice? |awk '{print $1}'
    – Tim
    Jul 26, 2013 at 18:06
  • If you just want to exclude spaces add that: [^\/ ]. What is your ultimate goal? It sounds like you are doing some tricky filename parsing / formatting, and usually that's never a clean and easy task.
    – jw013
    Jul 26, 2013 at 18:51

2 Answers 2


Since you clarified what you wanted in a comment to Gnouc's answer, here's a solution:

sed 's|[^ /]*/|--|g'

$ echo '45mb ./aaaa/bbbb/cccc/dddd' | sed 's|[^ /]*/|--|g'
45mb --------dddd

This will break if you have a trailing slash, or if the filepath you're passing to it contains any spaces. It would be pretty easy to script something a little more watertight, but it would involve more than a single line.

Here's one solution using capture groups:

sed -e 's|\([^ ]* \).*/\(.*\)|\1\2|'

I'm using |s as the separators because then I don't have to bother escaping the forward-slashes (but I would have to escape any |s in the pattern). AFAIK sed can have pretty much any character as a separator.

The first capture group \([^ ]* \) matches 'any number of any character except a blank space, followed by a blank space'. The .*/ matches 'any number of any characters, followed by a forward-slash', and the second group \(.*\) captures 'any number of any characters'.

Sed's regular expressions (and most regular expressions) are greedy by default, so .*/ will match the longest string that matches its pattern.

$ echo '45mb ./aaaa/bbbb/cccc/dddd' | sed 's|\([^ ]* \).*/\(.*\)|\1\2|'
45mb dddd

However, this will break if there is a trailing slash:

$ echo '45mb ./aaaa/bbbb/cccc/dddd/' | sed 's|\([^ ]* \).*/\(.*\)|\1\2|'

This version will work even with a trailing slash, but will break if you have more than one:

sed -e 's|\([^ ]* \).*/\(.\)|\1\2|'

$ echo '45mb ./aaaa/bbbb/cccc/dddd/' | sed 's|\([^ ]* \).*/\(.\)|\1\2|'
45mb dddd/
$ echo '45mb ./aaaa/bbbb/cccc/dddd//' | sed 's|\([^ ]* \).*/\(.\)|\1\2|'
45mb /

Here is solution using regex with perl:

$ echo '45mb ./aaaa/bbbb/cccc/dddd' | perl -ne 'print $1 if /(\.\/.*\/)/'

And substitution:

$ echo '45mb ./aaaa/bbbb/cccc/dddd' | perl -ple 's/(\.\/.*\/)/--/'
45mb --dddd
  • Thank you for the answers but i dont think i explained the end goal well enough. I want to run find ./ -maxdepth 1 -type d -print0 | xargs -0 du -h --max-depth 1 | sed -e 's/[^\/]*\//--/g;' to print a dir hierarchy with depth represented by -- for every sub-folder and at the start i want the dir size. At the moment the find and du will print what i want, and the sed will replace the dirs with -- but it also chops off the dir size from the start which i want left intact.
    – Flo Woo
    Jul 27, 2013 at 1:36
  • .. turns out sed doesn't support regex lookarounds so thats why i couldnt get it working. Accepting answer from Gnouc for perl example. The end solution was perl -ple 's/(?<=\/)[^\/]+\//--/g' thanks again
    – Flo Woo
    Jul 27, 2013 at 10:47

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.