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

  • 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 Mar 2 '16 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 Mar 27 '16 at 5:15
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
  • 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 Mar 2 '16 at 12:39
  • Getting unwanted results with the perl code, but the python seems to be working correctly. Thanks. – dparz Mar 2 '16 at 13:05
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">
  • 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 Mar 2 '16 at 11:45
  • ok I edit it, this works now! – wittich Mar 2 '16 at 11:52
  • Well maybe there is still a prob. how long is your url? How many subdirectories do you have? – wittich Mar 2 '16 at 11:56
  • Okay now it works also with subdirs. I had to schange i%2==0 to i==2! – wittich Mar 2 '16 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 Mar 2 '16 at 12:14
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">
  • 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 Mar 2 '16 at 11:40
  • @kos Thanks..did not notice..edited.. – heemayl Mar 2 '16 at 11:48
  • @dparz Check my edit – heemayl Mar 2 '16 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 Mar 2 '16 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 Mar 2 '16 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.

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.