Да, есть разделение слов.
Ну, технически, разделение командной строки при разборе строки bash.
Давайте сначала правильно цитируем:
Самое простое (и небезопасное )решение, позволяющее заставить команду работать так, как вы, как я полагаю, захотите, это:
bash -c "cd \"$myvar\""
Давайте подтвердим, что происходит (, предположивmyvar="/path to/my directory"
):
$ bash -c "printf '<%s>\n' $myvar"
<./path>
<to/my>
<directory>
Как видите, строка пути была разбита на пробелы. И:
$ bash -c "printf '<%s>\n' \"$myvar\""
<./path to/my directory>
Не разделен.
Однако команда (в том виде, в каком она написана ), небезопасна. Лучшее использование:
$ bash -c "cd -P -- \"$myvar\"; pwd"
/home/user/temp/path to/my directory
Это защитит cd от файлов, начинающихся с тире (-), или от перехода по ссылкам, которые могут привести к проблемам.
Это будет работать, если вы можете быть уверены, что строка в $myvar
является путем.
Однако «внедрение кода» по-прежнему возможно, поскольку вы «выполняете строку» :
$ myvar='./path to/my directory";date;"true'
$ bash -c "printf '<%s> ' \"$myvar\"; echo"
<./path to/my directory> Tue May 8 12:25:51 UTC 2018
Вам нужно более сильное цитирование строки, например:
$ bash -c 'printf "<%s> " "$1"; echo' _ "$myvar"
<./path to/my directory";date -u;"true>
Как вы можете видеть выше, значение не интерпретировалось, а просто использовалось как "$1'
.
Теперь мы можем (безопасно )использовать sudo:
$ sudo bash -c 'cd -P -- "$1"; pwd' _ "$myvar"
_: line 0: cd:./path to/my directory";date -u;"true: No such file or directory
Если аргументов несколько, можно использовать:
$ sudo bash -c 'printf "<%s>" "$@"' _ "$val1" "$val2" "$val3"
Расширение псевдонима — это просто замена текста, за которой следует еще один цикл разбора командной оболочкой.
При вводе
findRoute checkout
Сначала расширено до:
php artisan route:list | (head -n 3; grep $1) checkout
И этот результат снова анализируется как шелл-код. Здесь недопустимый шелл-код.
Вместо этого вы можете использовать сценарий или функцию. Нравится:
findRoute() {
php artisan route:list | {
head -n 3
grep -e "$1"
}
}
Имейте в виду, что head
может считывать более 3 строк, хотя выводит только 3, так как большинство head
реализаций считывают целые блоки. Это означает, что grep
не увидит эту часть.
Если ваш sed
является реализацией GNU, вы можете заменить head -n3
на sed -u 3q
, где sed
считывает ввод по одному байту за раз, чтобы не читать дальше третьих символов новой строки.
В качестве альтернативы вы можете использовать awk
вместо:
findRoute() {
php artisan route:list |
PATTERN=$1 awk 'NR <= 3 || $0 ~ ENVIRON["PATTERN"]'
}
Осторожно $1
затем интерпретируется как расширенное регулярное выражение (как дляgrep -E
)вместо базового (с grep
без -E
). Для поиска подстроки (, как в grep -F
), замените на:
findRoute() {
php artisan route:list |
PATTERN=$1 awk 'NR <= 3 || index($0, ENVIRON["PATTERN"])'
}