Удивительное расширение оболочки при усечении переменной, полученной звездочкой

В моей папке у меня есть следующие файлы:

roi_1_Precentral_L/
roi_1_Precentral_L_both.fig
roi_1_Precentral_L_left.fig
roi_1_Precentral_L_right.fig
roi_1_Precentral_L_slice.fig
roi_2_Precentral_R/
roi_2_Precentral_R_both.fig
...
roi_116_Vermis_10/
roi_116_Vermis_10_both.fig
roi_116_Vermis_10_left.fig
roi_116_Vermis_10_right.fig
roi_116_Vermis_10_slice.fig

Я использую следующий скрипт для получения желаемого префикса имени файла для каждого из 116 типов:

for iroi in `seq 1 116`;
do
    d=roi_${iroi}_*/
    d2=${d:0:-1}         # <-- THIS LINE IS IMPORTANT
    echo $d2
done;

Желаемый вывод для iroi = 1:

$ roi_1_Precentral_L

Фактический вывод:

$ roi_1_Precentral_L roi_1_Precentral_L_both.fig roi_1_Precentral_L_left.fig roi_1_Precentral_L_right.fig roi_1_Precentral_L_slice.fig

Как можно избежать расширения оболочки в выделенной строке кода для получения желаемого результата?

2 ответа

Решение

Если вы присваиваете массиву, глобус будет развернут в первой строке, а не позже echo как было с вашим оригинальным кодом.

d=( "roi_${iroi}_"*/ )
d2=${d:0:-1}            # Note that this only works with new bash. ${d%/} would be better.
echo "$d2"

Если вы ожидаете несколько каталогов, "${d[@]%/}" развернем до полного списка, с трейлингом / снято с каждого:

d=( "roi_${iroi}_"*/ )
printf '%s\n' "${d[@]%/}"

Что касается избежания нежелательных расширений - обратите внимание, что в приведенном выше описании каждое расширение, за исключением тех, которые находятся в правой части простого (строка, а не массив) назначения, заключено в двойные кавычки. (Регулярные присваивания неявно запрещают расщепление строк и расширение глобуса - хотя даже тогда не помешает иметь кавычки! ${d:0:-1} удалял / из самого выражения глобуса, а не из его результатов).

Ответ на вопрос

Если вы хотите, вы можете цитировать, чтобы избежать расширения * в $d...

d=roi_${iroi}_*/
d2="${d:0:-1}"
echo $d2

... но тогда вы могли бы напрямую написать...

d2="roi_${iroi}_*"
echo $d2

... и результат будет таким же, как в вашем вопросе.

Ответ на ожидаемый результат

Вы можете выполнить расширение в массиве и выбрать первую запись массива, а затем удалить / из этой записи.

for iroi in {1..116}; do
    d=(roi_"$iroi"_*/)
    d2="${d[0]:0:-1}"
    echo "$d2"
done

Это соответствует только каталогам и печатает первый каталог без завершающего /,

Другие вопросы по тегам