views:

37

answers:

2

For instance, I suppose I have a directory that contains the following folders

foo_bar
baz

What I would like to have is a bash command that will make a symlink foo-bar to foo_bar so it would look like this:

foo-bar
foo_bar
baz

I'm pretty sure I can write a Python script to do this, but I'm curious if there's a way to do this with bash. Here's where I'm stuck:

ls -1 | grep _ | xargs -I {} ln -s {} `{} | sed 's/_/-/'`

What I'm trying to do is run the command ln -s with the first argument being the directory name and the second argument being that name passed through sed s/_/-/. Is there another way to do this?

+3  A: 

Bash can substitute in strings!

for path in *_*; do [ -d "$path" ] && ln -s "$path" "${path//_/-}"; done

If you want to be more selective about what to apply it to, you could do something similar:

find . -type d [other tests...] | while read path; do [ -d "$path" ] && ln -s "$path" "${path//_/-}"; done

Or your ls ... | grep ... instead of the find, of course.

A helpful reference for string manipulation, including that substitution: Manipulating Strings.

Jefromi
Wow; I didn't know this. And I was calling sed all the time. =]
strager
@strager: sed is obviously much more powerful. This is just literal string substitution, not regex. But when that's what you need, it's nice to avoid spawning the extra process!
Jefromi
+2  A: 

I don't recommend parsing ls, but here's how you could use it with sed and 'xargs` to do what you want (it won't work if there are spaces in the filenames):

ls *_* | sed 'h;s/_/-/g;x;G;s/\n/ /' | xargs ln -s

However, I would do it the way Jefromi showed.

Dennis Williamson