I have a Windows path in a bash variable as a string:


I am trying to convert this path into a Linux path starting with /c/Users....

My attempt

The following works:

echo $file
> /c/Users/abcd/Downloads/testingFile.log


Here, I have done this for a string that contains the filepath. The reason I am asking this question is that I have to convert 20 such strings in a bash script in Ubuntu 16.04 and each time I do this I have to write 2 lines per conversion - it is taking up a lot of space!


Is there a way to combine the 2 commands


into one command?

  • 1
    Use a for loop (and maybe an array). Also quote your variables. – wjandrea Apr 4 '17 at 23:09
  • Thanks. Could you show an example of how to do this in a loop or array? – edesz Apr 4 '17 at 23:11

There would be a way to do both replacements at once using sed, but it's not necessary.

Here's how I would solve this problem:

  1. Put filenames in array
  2. Iterate over array

  # ... add more here ...

for f in "${filenames[@]}"; do
  echo "$f"

If you want to put the output into an array instead of printing, replace the echo line with an assignment:

  filenames_out+=( "$f" )
  • Ok.But if I had 2 files f1 and f2, how would that work? I mean, how do I re-assign the new filenames to the array by replacing the old ones? – edesz Apr 5 '17 at 0:15
  • @WR put em in a new array and use that. – muru Apr 5 '17 at 0:30
  • @WR Added that into the answer – wjandrea Apr 5 '17 at 1:56
  • 1
    I'd recommend to make a new array, for clarity's sake. – wjandrea Apr 5 '17 at 2:03

If it's something you want to do many times, then why not create a little shell function?

win2lin () { f="${1/C://c}"; printf '%s\n' "${f//\\//}"; }

$ file='C:\Users\abcd\Downloads\testingFile.log'
$ win2lin "$file"
$ file='C:\Users\pqrs\Documents\foobar'
$ win2lin "$file"
  • That's not a bad idea. However, it does not seem to give /c/Users... - instead it is giving C:\Users\.... – edesz Apr 5 '17 at 0:09
  • @WR apologies - copy-paste error. Please try it now. – steeldriver Apr 5 '17 at 0:17
  • 1
    Thanks, I use cdw () { f="${1/D://d}"; cd "/mnt${f//\\//}"; } in Windows subsystem for Linux, works like a charm! – Weekend May 8 '18 at 13:06

You would be able to achieve this in one line using sed

file="$(echo "$file" | sed -r -e 's|^C:|/c|' -e 's|\\|/|g')"

Note the two patterns must remain separate nonetheless as the matches are replaced by different substitutions.

  • 1
    Synonym: file="$(sed 's|^C:|/c|; s|\\|/|g' <<< "$file")" – wjandrea Apr 5 '17 at 2:01

Is this question still open to new suggestions? If so, would this help you?

$ file="/$(echo 'C:\Users\abcd\Downloads\testingFile.log'|tr '\\' '/')"
$ echo $file

Oh, and in case the C must be cast to lowercase:

file="/$(echo 'C:\Users\abcd\Downloads\testingFile.log'|tr '^C' 'c'|tr '\\' '/')"

As an overview:

$ file='C:\Users\abcd\Downloads\testingFile.log'
$ echo $file
$ file="/$(echo $file|tr '^C' 'c'|tr '\\' '/')"
$ echo $file
  • What is the reason for using '^C'? – edesz Apr 28 '17 at 0:20
  • 1
    ^ means start of the line, otherwise all occurences of C will become lowercase... should there be any – user680858 Apr 28 '17 at 7:25
  • I must add that the other suggestions also work. Many Unix command can do the same work, so its up to you what style of solution you prefer use. – user680858 Apr 28 '17 at 7:30
  • I had not asked earlier about ^ that has been used in some other answers here too. Thanks for the answer and the explanation. – edesz Apr 28 '17 at 16:16

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.