16

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

file='C:\Users\abcd\Downloads\testingFile.log'

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

My attempt

The following works:

file=${file/C://c}
file=${file//\\//}
echo $file
> /c/Users/abcd/Downloads/testingFile.log

Problem

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!

Question

Is there a way to combine the 2 commands

file=${file/C://c}
file=${file//\\//}

into one command?

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

4 Answers 4

19

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

filenames=(
  'C:\Users\abcd\Downloads\testingFile.log'
  # ... add more here ...
)

for f in "${filenames[@]}"; do
  f="${f/C://c}"
  f="${f//\\//}"
  echo "$f"
done

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

  filenames_out+=( "$f" )
4
  • 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, 2017 at 0:15
  • @WR put em in a new array and use that.
    – muru
    Apr 5, 2017 at 0:30
  • @WR Added that into the answer
    – wjandrea
    Apr 5, 2017 at 1:56
  • 1
    I'd recommend to make a new array, for clarity's sake.
    – wjandrea
    Apr 5, 2017 at 2:03
10

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"
/c/Users/abcd/Downloads/testingFile.log
$ 
$ file='C:\Users\pqrs\Documents\foobar'
$ win2lin "$file"
/c/Users/pqrs/Documents/foobar
3
  • That's not a bad idea. However, it does not seem to give /c/Users... - instead it is giving C:\Users\....
    – edesz
    Apr 5, 2017 at 0:09
  • @WR apologies - copy-paste error. Please try it now. Apr 5, 2017 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, 2018 at 13:06
3

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
  • 1
    Synonym: file="$(sed 's|^C:|/c|; s|\\|/|g' <<< "$file")"
    – wjandrea
    Apr 5, 2017 at 2:01
1

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
/C:/Users/abcd/Downloads/testingFile.log

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
C:\Users\abcd\Downloads\testingFile.log
$ file="/$(echo $file|tr '^C' 'c'|tr '\\' '/')"
$ echo $file
/c:/Users/abcd/Downloads/testingFile.log
4
  • What is the reason for using '^C'?
    – edesz
    Apr 28, 2017 at 0:20
  • 1
    ^ means start of the line, otherwise all occurences of C will become lowercase... should there be any
    – user680858
    Apr 28, 2017 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, 2017 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, 2017 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.