Глобирование / расширение пути с двоеточием в качестве разделителя

Как я могу преобразовать строку, содержащую символы глобуса, такие как

/var/lib/gems/*/bin

в разделенную двоеточиями строку имен файлов (т. е. PATH-совместимых), соответствующих шаблону?

т.е. echo /var/lib/gems/*/bin вернусь

/var/lib/gems/1.8/bin /var/lib/gems/1.9.1/bin

я хочу

/var/lib/gems/1.8/bin:/var/lib/gems/1.9.1/bin 

вместо.

Очевидный подход - просто заменить символ пробела на ":" через tr, но это не работает, если само имя файла содержит символ пробела.

8 ответов

Решение

На самом деле, я подумал о лучшем решении: использовать функцию оболочки.

function join() {
    local IFS=$1
    shift
    echo "$*"
}

mystring=$(join ':' /var/lib/gems/*/bin)

Это должно сделать это для вас:

dirs=(/var/lib/gems/*/bin)    # put filenames (dirnames) in an array
saveIFS=$IFS IFS=':'          # set the Internal Field Separator to the desired delimiter
dirs=("${dirs[*]}")           # convert the array to a scalar with the new delimiter
IFS=$saveIFS                  # restore IFS
PATH="$(printf "%s:" /usr/*/bin)"
PATH="${PATH%:}"

Это довольно тривиально, если вы загляните в Perl:

perl -e 'print join ":", @ARGV' /var/lib/gems/*/bin

Или Python:

python -c 'import sys; print ":".join(sys.argv[1:])' /var/lib/gems/*/bin

Или любое количество других популярных языков сценариев.

Не нужно связываться с IFS, zsh может объединять массивы с простым переменным флагом:

dirs=(/var/lib/gems/*/bin(N))
dirs=${(j.:.)dirs}

(N) в первой строке подавляется предупреждение, если файлов нет; (j.:.) присоединяется к массиву с :s. Работает с 0, 1 или несколькими совпадениями.

Без сохранения IFS и подстановки команд

dirs=(/var/lib/gems/*/bin) ; IFS=: eval 'dirs="${dirs[*]}"'
printf "%s\n" /var/lib/gems/*/bin | tr "\n" ":"

Еще один вкладчик: printf "%s\n" /var/lib/gems/*/bin | paste -s -d':'

Но на мой взгляд, ответ @timo лучше.

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