Windows filepath перетворений на Linux filepath


13

У мене шлях Windows до bash змінної у вигляді рядка:

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

Я намагаюся перетворити цей шлях у шлях Linux, починаючи з /c/Users....

Моя спроба

Наступні роботи:

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

Проблема

Тут я зробив це для рядка, який містить шлях файлу. Причиною, що я задаю це питання, є те, що мені доводиться конвертувати 20 таких рядків у сценарій bash в Ubuntu 16.04, і кожен раз, коли я це роблю, я повинен писати 2 рядки за перетворення - це займає багато місця!

Питання

Чи є спосіб поєднати 2 команди

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

в одну команду?


1
Використовуйте цикл (і, можливо, масив). Також цитуйте свої змінні.
wjandrea

Спасибі. Чи можете ви показати приклад того, як це зробити у циклі чи масиві?
edesz

Відповіді:


17

Існував би спосіб зробити обидві заміни одночасно, використовуючи sed, але це не обов'язково.

Ось як я вирішив цю проблему:

  1. Покладіть назви файлів у масив
  2. Ітерація над масивом

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

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

Якщо ви хочете помістити вихід у масив замість друку, замініть echoрядок на призначення:

  filenames_out+=( "$f" )

Добре, але якби у мене було 2 файли, f1і f2як би це працювало? Я маю на увазі, як я можу призначити нові імена файлів до масиву, замінивши старі?
edesz

@WR покладіть їх у новий масив і скористайтеся цим.
муру

@WR Додав це до відповіді
wjandrea

1
Я б радив зробити новий масив, для наочності.
wjandrea

9

Якщо ви хочете зробити багато разів, то чому б не створити маленьку функцію оболонки?

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

Це не погана ідея. Однак, схоже, це не дає /c/Users...- натомість дає C:\Users\....
edesz

Вибачення @WR - помилка копіювання та вставки. Спробуйте зараз.
steeldriver

1
Дякую, я використовую cdw () { f="${1/D://d}"; cd "/mnt${f//\\//}"; }в підсистемі Windows для Linux, працює як шарм!
вихідні

2

Ви могли б досягти цього за один рядок, використовуючи sed

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

Зверніть увагу, що два шаблони повинні залишатися окремими, оскільки збіги замінюються різними замінами.


1
Синонім:file="$(sed 's|^C:|/c|; s|\\|/|g' <<< "$file")"
wjandrea

1

Це питання все ще відкрите для нових пропозицій? Якщо так, чи допоможе вам це?

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

О, і у випадку, якщо С повинен бути переданий у малі регістри:

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

Як огляд:

$ 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

У чому причина використання '^C'?
edesz

1
^ означає початок рядка, інакше всі випадки C стануть малими літерами ... якщо такі будуть

Треба додати, що інші пропозиції також спрацьовують. Багато команд Unix можуть виконувати ту саму роботу, тож залежати від того, який стиль рішення ви віддаєте перевагу.

Я раніше не питав про ^те, що використовується в деяких інших відповідях і тут. Дякую за відповідь та пояснення.
edesz
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.