Объявление переменной параллельным sh -c …

Я пытался обработать вывод find с помощью parallel , который, в свою очередь, вызывал оболочку (некоторые текстовые подстановки были необходимы). Я заметил странное поведение, которое я не могу объяснить себе.

В каждом каталоге есть куча файлов, назовите их file1.xtc , file2.xtc . Некоторые из них имеют имена, такие как file1.part0002.xtc и т. Д. Если файл, переданный из find имел имя *.part000x.* , Мне нужно удалить *.part000x.* , Так что результирующая команда будет похожа на

 command -f file1.part0001.xtc -s file1.tpr 

Я использовал find и parallel этому эффекту, но parallel подстановки (в частности, бит {.} ) Не совсем достаточны (они удаляют расширение .xtc , оставляя только .part0001 ), поэтому вот команда, которую я использовал для проверки мой результат:

 find 1st 2nd 3rd -name '*.xtc' -print0 | parallel -0 sh -c 'name=""; name="{.}"; echo {.} ${name%.*}.tpr' 

Если я использую указанную выше команду, сначала объявляя name и присваивая ему пустую строку (или что-то еще в этом случае), результат

 file1.part0001 file1.tpr 

(это имена, которые мне нужно использовать для моей команды). Если, однако, я запускаю этот

 find 1st 2nd 3rd -name '*.xtc' -print0 | parallel -0 sh -c 'name="{.}"; echo {.} ${name%.*}.tpr' 

результат:

 file1.part0001 .tpr 

или он ведет себя так, как будто $name не существует.

Поэтому мои вопросы:

– Какова причина такого поведения?

– Какой был бы предпочтительный способ борьбы с ним?

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

Выход sh --version

 GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11) 

вывода новой версии bash которую я установил и использовал вместо sh в приведенной выше команде (с тем же эффектом) ( /usr/local/bin/bash --version )

 GNU bash, version 4.2.0(1)-release (i386-apple-darwin11.4.2) 

One Solution collect form web for “Объявление переменной параллельным sh -c …”

Ваша проблема не имеет ничего общего с bash. На самом деле, поскольку вы говорите parallel чтобы запустить sh , вы даже не можете использовать bash .

Проблема заключается в том, что параллель на самом деле не является заменой для xargs, как указывает ее документация. Вместо этого он накапливает свои аргументы в одну строку (с пробелами между ними), а затем интерпретирует это как последовательность команд. Итак, в вашем случае у вас есть:

 sh -c 'name="{.}"; echo {.} ${name%.*}.tpr' 

который интерпретируется как

 sh -c 'name="{.}"; echo {.} ${name.*}.tpr 

Так как это две отдельные команды, а первая выполняется в подоболочке ( sh -c ), $name не устанавливается во втором.

Теперь вы можете добавить что-нибудь к началу строки, например true :

 sh -c 'true; name="{.}"; echo {.} ${name%.*}.tpr' 

Это будет интерпретироваться как:

 sh -c 'true' name="{.}" echo {.} ${name%.*}.tpr' 

В этом случае вызов sh – это, по сути, отбрасывание; то name устанавливается в среде, поддерживаемой parallel и, наконец, echo вызывается с набором name .

Таким образом, казалось бы, самое простое решение – просто избавиться от ненужного вызова sh :

 find 1st 2nd 3rd -name '*.xtc' -print0 | parallel -0 'name={.}; echo {.} "${name%.*}.tpr"' 

Примечание. Основываясь на подсказке @StephaneChazelas, я удалил кавычки вокруг {.} И добавил их вокруг ${name%.*}.ptr . Параллель делает свою собственную цитату из своих собственных подстановок, которая каким-то странным образом вмешивается в явные кавычки. Однако он не добавляет цитирования к заменам оболочки, которые следует указывать, если есть какая-либо возможность замены слова split.

Другой вариант, если вы действительно хотите использовать подоболочку по какой-либо причине (или конкретной подоболочке), будет использовать параметр -q :

 find 1st 2nd 3rd -name '*.xtc' -print0 | parallel -0 -q sh -c 'name="{.}"; echo "{.}" "${name%.*}.tpr"' 

Примечание. Как и выше, я скорректировал кавычки. В этом случае явный -q подавляет цитирование подстановок, поэтому вы должны их явно процитировать. Однако это текстовая цитата, которая менее точна, чем цитирование оболочки; если подстановка включает символ двойной кавычки, этот символ не будет экранирован, поэтому он закроет явные кавычки, сломав командную строку и эффективно внедряя уязвимость ввода команд (вы получите другие проблемы для имен файлов, содержащих $ , , или \ characters). Для этого, помимо других причин, опция -q не рекомендуется.

  • Как установить переменную среды оболочки из файла autotools .am?
  • grep переменная в выражении if
  • Как использовать глобальные переменные массивы в псевдонимах или функциях
  • Как назначить вывод команды переменной без запуска команды в подоболочке?
  • Как использовать тройник для захвата STDOUT из кодового блока в имя файла, определенное в блоке?
  • Создать переменную на основе порядка, в котором файл находится в алфавитном списке файлов
  • Присвоение нового значения непосредственно в индекс символа значения в массиве с zsh
  • Сценарий Bash для заполнения шаблона
  • Поведение задания массива
  • Может ли awk использовать идентификаторы полей также для строк оболочки (переменных)?
  • Назначить имя хоста переменной в ksh
  • Linux и Unix - лучшая ОС в мире.