bash: синтаксическая ошибка рядом с неожиданным токеном `foo'

Да, есть разделение слов.
Ну, технически, разделение командной строки при разборе строки 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"
0
26.02.2020, 23:00
1 ответ

Расширение псевдонима — это просто замена текста, за которой следует еще один цикл разбора командной оболочкой.

При вводе

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"])'
}
4
28.04.2021, 23:22

Теги

Похожие вопросы