1

I'm new to the forum so please forgive any syntactical errors in my question.

I'm trying to replace spaces with underscores in a matched substring only. I figured sed would be the best editor for this but I cannot find the proper code to do this.

Sample line from file1 below:

Some text before pattern to match href="./Dynamic Directory name - Junk_files/irrelevant stuff after match">

Would like to change to this:

Some text before pattern to match href="./Dynamic_Directory_name_-_Junk_files/irrelevant stuff after match">

I thought I was close with this cat file1 |sed '/\.\/.*. Junk_files/ { s/ /_/g; }' but all it did was replace all spaces on the matched line with underscores.

Any help with this would be greatly appreciate. Thanks

2
  • You're asking for a sed solution, but you're clearly unsatisfied with the answers. That's because sed (and other text-processing tools) are extremely limited when it comes to parsing HTML. You might want to add more examples, remove the sed tag and ask for a solution which won't necessarily have to involve sed or other text-processing tools.
    – kos
    Commented Mar 2, 2016 at 12:43
  • Is this for text in a file or would you actually like to do this for filenames? There is an easy way to do this for all the filenames in a directory.
    – mchid
    Commented Mar 27, 2016 at 5:15

4 Answers 4

2

Try this, it finds the first pair of slashes and removes all spaces between!

 awk -F'/' '{for(i=2;i<=NF;i++)if(i==2)gsub(" ","_",$i);}1' OFS="/"

Example

file='href="./Dynamic Directory name - Junk_files/irrelevant stuff after match">' 
echo $file | awk -F'/' '{for(i=2;i<=NF;i++)if(i==2)gsub(" ","_",$i);}1' OFS="/"
# Output: 
href="./Dynamic_Directory_name_-_Junk_files/irrelevant stuff after match">
8
  • This example replaces every space in the file with underscores. I need only the spaces in the folder name to be replaced with underscores.
    – dparz
    Commented Mar 2, 2016 at 11:45
  • ok I edit it, this works now!
    – wittich
    Commented Mar 2, 2016 at 11:52
  • Well maybe there is still a prob. how long is your url? How many subdirectories do you have?
    – wittich
    Commented Mar 2, 2016 at 11:56
  • Okay now it works also with subdirs. I had to schange i%2==0 to i==2!
    – wittich
    Commented Mar 2, 2016 at 12:06
  • Pls accept it as correct answer if it works for you. If there is a better answer coming you can always change your choice.
    – wittich
    Commented Mar 2, 2016 at 12:14
1

Through python,

$ echo 'href="./Dynamic Directory name - Junk_files/irrelevant stuff after match"' |
> python -c "import re;
> import sys;
> print re.sub(r'(?<=\./).*?(?=/)', lambda m: m.group().replace(' ', '_'), sys.stdin.read())
> "
href="./Dynamic_Directory_name_-_Junk_files/irrelevant stuff after match"

Through perl,

$ echo 'href="./Dynamic Directory name - Junk_files/irrelevant stuff' | perl -pe '
> s/\s(?=(?:(?!\.\/).)*?\/)/_/g
> '
href="./Dynamic_Directory_name_-_Junk_files/irrelevant stuff
2
  • They both seem to be working, so +1. However most likely the full line is Some text before pattern to match href="./Dynamic Directory name - Junk_files/irrelevant stuff after match"> (by the way the commands are just not copy-pastable, you might want to fix that).
    – kos
    Commented Mar 2, 2016 at 12:39
  • Getting unwanted results with the perl code, but the python seems to be working correctly. Thanks.
    – dparz
    Commented Mar 2, 2016 at 13:05
0

It's better to use an XML parser.

If you insist on using sed; assuming the pattern stays consistent:

sed -r 's#^([^/]+/[^ ]+) ([^ ]+) ([^ ]+) - ([^ ]+/)#\1_\2_\3_-_\4#' file.txt

This will replace all spaces between two forward slashes (/) with underscores (_). As the input contains /, i have used # as the pattern separator for sed.

Example:

% sed -r 's#^([^/]+/[^ ]+) ([^ ]+) ([^ ]+) - ([^ ]+/)#\1_\2_\3_-_\4#' <<<'Some text before pattern to match href="./Dynamic Directory name - Junk_files/irrelevant stuff after match">'
Some text before pattern to match href="./Dynamic_Directory_name_-_Junk_files/irrelevant stuff after match">
6
  • This only adds underscores before and after the dash in the folder name. I need all spaces in the folder name to be replaced with underscores. The consistent pattern would be href"./Folder name with spaces - Junk_files/.
    – dparz
    Commented Mar 2, 2016 at 11:40
  • @kos Thanks..did not notice..edited..
    – heemayl
    Commented Mar 2, 2016 at 11:48
  • @dparz Check my edit
    – heemayl
    Commented Mar 2, 2016 at 11:48
  • Doesn't work if the folder name longer. eg. file='href="./Dynamic Directory name - Junk_files is sometimes longer/irrelevant stuff after match/test test/">'. See my example it works: askubuntu.com/a/741165/189996
    – wittich
    Commented Mar 2, 2016 at 12:11
  • This works but is limited to a static count of spaces. The folder names in the files I need to edit can vary in the amount of spaces that are in them. Your code works on the original example provided, but does not work on either of these: [Here is another href="./Here is a very long folder name to test - Junk_files/blahblah.css"] or [Smaller folder href="./Cat - Junk_files/].
    – dparz
    Commented Mar 2, 2016 at 12:11
0

That's HTML, and unless you have a very well defined a simple enough subset of HTML in your file, parsing HTML using regular expressions is a pretty bad idea.

This Perl one-liner works for replacing that substring in that specific context:

printf 'Some text before pattern to match href="./Dynamic Directory name - Junk_files/irrelevant stuff after match">\n' | perl -ne 'if(/(.*?")(.*\/)(.*)/){$x = $1; $y = $2; $z = $3; $y =~ s/ /_/g; print("$x$y$z")}'

Meaning: it will just replace spaces with underscores in the first " and / delimited substring found. But that's about it. If you're parsing a complex document, don't use it. You could make the pattern more strict (for example you could use /href=(.*?")(.*\/)(.*)/ and print("href=$x$y$z")), but that could still fail upon any occurrence of /href=(.*?")(.*\/)(.*)/.

Unless you're parsing a very well defined and simple enough subset of HTML in your file and you're sure something like that won't fail, just use an HTML parser.

You must log in to answer this question.

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