Будівництво доріжок надійно


16

Скажіть, у мене в скрипті оболонки є кілька змінних (наприклад, в zsh):

FOLDER_1, FOLDER_2, etc.

Ці змінні відносяться до папок, що походять від /. Наприклад, якщо у мене є шлях/home/me/stuff/items

змінні будуть:

FOLDER_1='home'
FOLDER_2='me'
FOLDER_3='stuff'

Тепер скажіть, що я хочу зібрати відповідний шлях шляхом об'єднання змінних. Один з можливих способів - побудувати шлях таким чином:

PATH=$FOLDER_1/$FOLDER_2/$FOLDER_3/

Однак скажіть, що деякі змінні FOLDER_iпоставляються з косою косою вперед, а інші - (і ми не знаємо, яка), наприклад

FOLDER_1='home'
FOLDER_2='stuff/'
FOLDER_3='items'

Моє запитання: Як я міг грунтовно побудувати шлях? (наприклад, уникнення подвійних нахилів і додавання їх там, де вони повинні бути).

Я думав, що один із способів зробити це - додати /завжди між парами змінних, а потім видалити всі дублікати за допомогою sed, але я не можу змусити його працювати (я не впевнений, що в ньому /правильно поводиться sed).

Крім того, я вигадую колесо ? (тобто є якась вбудована, яка вже робить це?).

Зрештою, якщо змінні знаходяться в масиві , наприклад FOLDERS, чи можна це зробити без циклу? (або альтернативно, циклічно, але не знаючи, скільки FOLDERSїх у масиві).

Відповіді:


12

Ви можете використовувати printfз масивом:

parts=("$FOLDER_1" "$FOLDER_2" "$FOLDER_3");
printf '/%s' "${parts[@]%/}"
# Use "printf -v path" to save it into a variable called "path" instead of printing it

У %цьому випадку оператор обрізає кінцеві рядки /. Застосовуючи його parts[@], він обрізає кожен елемент масиву окремо.

Ключовим моментом для розуміння цього printfфокусу є цей біт із man 1 printf: "Рядок формату повторно використовується стільки разів, скільки потрібно для задоволення аргументів."


Один %метод працює для однієї кінцевої косої риси, згаданої в квестоні. Задовольняти, коли є декілька косої риси, ${parts[@]%%/*}працює. Ось посилання на трохи більше інформації про тестую рису: Що означають подвійні косої риски на шляху UNIX? Чи 'cd dir / subdir // дійсний ...
Peter.O

2
@fered: /*в цьому випадку це не означає нуль і більше косої риски , а скоріше косу рису, яку слід супроводжувати будь-якою кількістю символів. Це означає, що якщо ваш шлях починається з косої риски, результатом буде порожня рядок!
l0b0

Я вважав, як на прикладі, що буде лише косою косою рисою. Однак пристосуватись до можливості провідної косої риси, bash's extglob(з регулярним виразом) можна за допомогою .. shopt -s extglob; ${parts[@]%%/+(/)}...
Peter.O

15

Проста відповідь - перестати хвилюватися і полюбити декілька косих. Кілька косої риски мають такий же ефект, як і одна косою косою рисою (за винятком того, що шлях, що починається з, //має різні значення для кількох систем; шари емуляції Unix у Windows - єдині, кого я можу назвати). Це було задумано, і можливість збирати імена файлів, не турбуючись про декілька косої риски, була головною частиною цього дизайнерського рішення.

Для приєднання елементів масиву в zsh можна використовувати j прапор розширення параметра .

dir=${(j:/:)FOLDERS}

Ви можете прищипувати дублікати косого риса, поки ви на ньому, але це суто косметично.

setopt extended_glob
dir=${${(j:/:)FOLDERS}//\/\/##/\/}

У ksh та bash ви можете приєднатися до масиву, використовуючи перший символ $IFSяк роздільник. Потім ви можете скосити повторювані косі риски. У баш, вам потрібно буде це зробитиshopt -s extglob щоб увімкнути глобус ksh в останньому рядку фрагмента нижче.

IFS=/
dir="${FOLDERS[*]}"
unset IFS
dir=${dir//\/+(\/)//}

3

Як sedне працює для вас? Спробуйте sed 's|/\+|/|g'після об'єднання чи sed 's|/||g'раніше.


1

bash 4 введено розширене глобулювання, що дозволяє регулярно співставити вирази при заміні параметрів ${var....} ... Вимкнено за замовчуванням. Щоб увімкнути його для вашого сценарію, просто встановіть опцію оболонки extglob ...

Якщо припустити, що $ dir ==/home/me/////////stuff//items

shopt -s extglob; dir="${dir//+(\/)//}"

Отримана вартість $ dir

/home/me/stuff/items  

Ось декілька прикладів, що стосуються do-s та don-s - Bash Extended Globbing

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