Правильное использование кавычек при подстановке команд – как?

В довольно большом проекте я столкнулся со следующей проблемой: при вычислении правильной команды в bash-скрипте мне не удается заставить скрипт соблюдать двойную кавычку, необходимую для одиночных аргументов с пробелом.

$ ./testo "two three"
ls -l "two three_DD_FF"  # <- Why does it look for two files HERE??
ls: cannot access '"two': No such file or directory
ls: cannot access 'three_DD_FF"': No such file or directory

«два три» — единственный аргумент.

С two_three мой код работает, как и следовало ожидать:

$ ./testo two_three
ls -l "two_three_DD_FF"
ls: cannot access '"two_three_DD_FF"': No such file or directory

И это основной общий код, который я мог бы придумать:

#!/usr/bin/bash
cmd = "ls -l"
trio = ""'"'"${1}_DD"
trio = "${cmd} ${trio}_FF"'"'""
echo ${trio}
${trio}

(Я не нашел менее странного метода, чем приведенный выше, для странно выглядящей сильной цитаты, но это не моя главная забота.)

Чего я не понимаю, так это проблемы с исполнением: ls -l "two three_DD_FF" в строке выше по-прежнему приводит к поиску двух файлов, несмотря на двойные кавычки; в то время как та же строка в командной строке выполняет свою работу по назначению (то есть ищет файл «two three_DD_FF":

$ ls -l "two three_DD_FF"
-rw-rw-r-- 1 myhome me 0 Aug 27 13:09 'two three_DD_FF'

То есть строка echo ${trio} показывает правильную команду (по крайней мере, если она выполняется в командной строке; в то время как та же команда, если она выполняется из сценария, завершается неудачно. Она не учитывает двойные кавычки для имени файла, подлежащего поиску.

Мои вопросы:

  1. Почему одна и та же команда не выполняется из сценария?
  2. Конечно, как мне исправить сценарий, чтобы вызов фактически приводил к правильному результату?

Ваш ls может быть какой-нибудь странной проверкой псевдонима, вот так type ls

Ivan 27.08.2024 13:51

Цитирование "two three" помогает им быть одним аргументом в $1, а не разделяться на $1, $2. Но если вы затем запустите ls -l $1, что, по сути, и делаете, поскольку $1 не заключен в кавычки, он будет разделен. Другими словами, кавычки не «сохраняются» в переменной. Вы это вроде уже понимаете, так как иначе по вашей логике cmd = "ls -l" тоже не должно работать, так как не было бы разделения.

Verpous 27.08.2024 14:15

Вставьте свой скрипт на shellcheck.net для проверки/рекомендации. Имхо, никакая цитата не сможет исправить ваш сценарий.

Jetchisel 27.08.2024 14:56

Этот вопрос похож на: Почему оболочка игнорирует символы кавычек в аргументах, передаваемых ей через переменные?. Если вы считаете, что это другое, отредактируйте вопрос, поясните, чем он отличается и/или как ответы на этот вопрос не помогают решить вашу проблему.

tjm3772 27.08.2024 15:00

Кавычки, заключенные в trio, являются буквальными, а не синтаксическими, поэтому их нельзя использовать для предотвращения разделения слов.

tjm3772 27.08.2024 15:01

Какой ответ вы получите, если нажмете type ls?

user1934428 27.08.2024 15:53

Уточните: сценарий testso, по которому вы звоните сюда, представляет собой странный небольшой сценарий bash, который вы разместили в своем вопросе?

user1934428 27.08.2024 15:57

Я голосую за закрытие этого вопроса, потому что автор не запустил свой скрипт сначала через shellcheck.net , как указано в теге bash.

Ed Morton 27.08.2024 16:07

То, как вы называете сценарий, имеет значение, что вы в нем пишете. Если вы напишете ${trio} без кавычек, он всегда будет разделяться на пробелы, независимо от содержания. Вам придется прописать в скрипте конструкции, предотвращающие разбиение, но используя кавычки, которые вы пишете, а не генерируете, например ls -l "$trio". Вы не можете хранить команды в переменной — используйте функцию для хранения команд. Обязательно к прочтению mywiki.wooledge.org/BashFAQ/050 .

KamilCuk 27.08.2024 16:12

Спасибо за подсказку с массивами. И благодаря подсказке @Ed Morton. Однако закрывать вопрос, потому что кто-то (кто??) решил, что речь идет не о программировании, и голосовать против него, смешно. Сайт вопросов не должен отпугивать пользователей от вопросов, которые другие считают «слишком простыми» или что-то в этом роде.

udippel 28.08.2024 12:06

К сожалению, не существует конкретной причины, по которой можно было бы нажать на ссылку «не следовал инструкциям тега», вам нужно ввести это вручную, и сайт просто выбирает одну из имеющихся у него групп, на которую можно нажать, чтобы отобразить ее в качестве причины закрытия, если кто-нибудь нажал на один из них. На самом деле ваш вопрос не был закрыт из-за того, что он не касался программирования или был слишком простым, а потому, что код содержит ошибки, о которых говорила проверка оболочки, о которой тег bash, который вы использовали, говорит вам использовать перед публикацией вопроса о bash. о вас (и поэтому многим людям, читающим ваш код, не придется обращаться).

Ed Morton 28.08.2024 14:23

@udippel: Одна проблема с вашим вопросом заключается в том, что вы задали два вопроса (почему это не удается? Как мне лучше написать?), и здесь вы видите, почему: пользователь Wiimm дал вам лучшее объяснение, почему это нужно делать, но без объяснений. почему ваш код не работает. Я дал вам объяснение, почему это не удается, но альтернативного решения нет. Теперь, если вы хотите принять ответ, какой из двух вы могли бы принять? Это основная причина, по которой у вас должен быть только один вопрос — это позволит вам выбрать лучший ответ.

user1934428 29.08.2024 10:12

Кроме того, ваша пометка странная. Например, вы отметили это как double, хотя в вашем вопросе нет ничего, связанного с типом C или C++ double. Кроме того, я не вижу особой значимости тега выполнения, поскольку у вас нет проблем с фактическим запуском/выполнением процесса.

user1934428 29.08.2024 10:18
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
13
65
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Моя рекомендация: работайте с массивами:

#!/usr/bin/env bash
cmd=(ls -l)
trio=( "${cmd[@]}" "${1}_DD_FF" )
"${trio[@]}"

Заменив echo в вашем скрипте на xxd <<< ${trio}, мы увидим:

00000000: 6c73 202d 6c20 2274 776f 2074 6872 6565  ls -l "two three
00000010: 5f44 445f 4646 220a                      _DD_FF".

Таким образом, ваша переменная trio содержит строку ls -l "two three_DD_FF".

Когда вы запускаете ${trio}, который можно было бы записать проще как $trio, bash применяет к строке разделение слов, что дает следующие слова:

0: ls
1: -l
2: "two
3: three_DD_FF"

Следовательно, ls вызывается с параметром опции (-l) и двумя дополнительными аргументами, "two и three_DD_FF".

Это отражено в сообщении об ошибке о том, что "two и three_DD_FF" не найдены.

Хороший ясный ответ. Но почему у вас есть обратные кавычки на первых двух пунктах вашего списка 0–4? Должно быть просто: 0: ls потом 1: -l потом 2: "two потом 3: three_DD_FF".

Raven 29.08.2024 10:06

@Raven: Понятия не имею, почему они туда попали. Я удалил их. Спасибо, что рассказали мне.

user1934428 29.08.2024 10:07

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