Bash сценарий дает 'Permission denied' при попытке указать путь к файлу в sed - PullRequest
0 голосов
/ 03 августа 2020

Я пытаюсь создать сценарий bash, который находит все файлы в моем каталоге dotfiles и связывает их с символическими ссылками в ~. Если каталог, в котором находится файл, не существует, он должен быть создан.

Скрипт в его нынешнем виде просто пытается найти файлы и создать два пути, когда это работает «реальный» и «символическая ссылка» будет использоваться с ln -s. Однако при попытке сохранить строки в «реальных» и «символических» я получаю только line 12: ./.zshrc: Permission denied

Что я делаю не так?

#!/bin/bash

dotfiles=()

readarray -d '' dotfiles < <(find . -type f ! -path '*/.git/*' ! -name "README.md" -type f -print0)

for file in ${dotfiles[@]}; do
                dir=$(dirname $file | sed s#.#$HOME#1)
                [ ! -d $dir ] && echo "directory $dir not exist!" && mkdir -p $dir
                
                # Create path strings
                real=$("$file" | sed s#.#$PWD#1)
                symlink=$("$file" | sed s#.#$HOME#1)
                echo "Real path: $cur"
                echo "Symbolic link path: $new"
done

exit

PS, я bash noob, и я в основном пишу этот сценарий для обучения.

1 Ответ

0 голосов
/ 03 августа 2020

Вот рефакторинг, который пытается исправить очевидные проблемы. Подробнее см. Комментарии с # .... Вероятно, также проверьте с помощью http://shellcheck.net/, прежде чем обращаться за помощью.

Непосредственной причиной сообщения об ошибке является то, что $("$file" ...) действительно пытается запустить $file как команду и захватить его вывод. Вы, вероятно, имели в виду $(echo "$file" ...), но этого часто можно избежать.

#!/bin/bash

dotfiles=()
readarray -d '' dotfiles < <(find . -type f ! -path '*/.git/*' ! -name "README.md" -type f -print0)

# ... Fix broken quoting throughout
for file in "${dotfiles[@]}"; do
    dir=$(dirname "$file" | sed "s#^\.#$HOME#")  # ... 1 is not required or useful
    # ... Use standard error for diagnostics
    [ ! -d "$dir" ] && echo "$0: directory $dir does not exist!" >&2 && mkdir -p "$dir"
    
    # Create path strings
    # ... Use parameter substitution
    real=$PWD/${file#./}
    symlink=$HOME/${$file#./}
    # ... You mean $real, not $cur?
    echo "Real path: $real"
    # ... You mean $symlink, not $new?
    echo "Symbolic link path: $symlink"
done
# ... No need to explicitly exit; trust me, you will anyway
#exit

Это просто синтаксические c исправления; Я бы, вероятно, избегал хранить результаты из find в массиве и просто l oop поверх них напрямую, и я не проверял, действительно ли logi c делает то, что (мы могли бы догадаться) вы, возможно, пытаетесь сделать .

См. Также Цикл по парам значений в bash для аналогичных topi c и Когда заключать в кавычки переменную оболочки? .

У скрипта все еще есть досадное предположение, что он будет запущен в каталоге dotfiles. Вероятно, лучшим решением было бы явно запустить find в этом каталоге и соответственно выполнить рефакторинг.

sed 's/x/y/' заменит первое вхождение x на y в каждой строке по определению и по дизайну ; нет причин или необходимости явно добавлять 1 после последнего разделителя. (Некоторые варианты sed позволяют номеру выбрать другое совпадение, чем первое, но это не переносимо; и, конечно, указывать первое совпадение, когда оно уже установлено по умолчанию, просто глупо. Существует флаг g для замены все совпадения, а не только первые, которые многие новички хотят использовать везде, но, конечно, это тоже не обязательно и не полезно.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...