Краткий ответ: см. BashFAQ # 50 .
Длинный ответ: когда bash анализирует строку, он анализирует кавычки и разделители команд (|
и т. Д.) Перед выполнением подстановки переменной;в результате он запускает $1 &
в функции, кавычки и труба в значении $ 1 никогда не анализируются, они просто передаются команде (в данном случае usr / bin / find) как частьАргумент.Чистый результат: на самом деле он работает в эквиваленте /usr/bin/find $findme_path -iname '"*.gpx"' -print0 '|' xargs -0 $other_command"
.
Обычно, в подобных случаях, я бы рекомендовал передать команду в виде последовательности слов (т.е. запустить функцию "$@" &
и вызватьэто как dosomething /usr/bin/find $findme_path -iname "*.gpx" -print0
, но даже это не будет обрабатывать канал в команде - это все равно будет рассматриваться как еще один аргумент.
Одна из возможностей - использовать eval
. Этого следует избегать, есливообще возможно, потому что eval
- это хороший способ создания ошибок сценариев - массивных ошибок, скрытых ошибок, непонятных ошибок, ошибок безопасности ... Он добавляет дополнительный уровень синтаксического анализа к всему в командестрока, которая означает, что, например, если вы пытаетесь оперировать файлом с именем Fred's file.txt
, он примет этот апостроф в качестве кавычки и будет очень запутан. Работа с файлами, в которых есть обратные кавычки, слишкомужасно созерцать. В основном, это плохие новости.
После быстрого взгляда на реальный сценарий я бы порекомендовал сочетание стратегий: скрыть как можно большеОн задает сложность в функциях оболочки, поэтому вы не пытаетесь передать каналы и перенаправления в функцию dosomething
, а затем используете подход с последовательностью слов, который я упоминал ранее.Для сценария, о котором идет речь, я бы сделал:
#!/bin/bash
dosomething () {
# code
printf "%q " "$@" >> ~/test.txt # this gives a much better idea what's being done than echo $1 would
"$@" &
# more code
}
# hide the pipeline in a shell function
find_and_do_something () {
/usr/bin/find "$1" -iname "*.gpx" -print0 | xargs -0 $other_command
}
main () {
# other code
dosomething /usr/bin/rsync $rsync_options
dosomething find_and_do_something "$findme_path"
# another code
}
( main | (zenity --progress $zenity_options || $still_another_command ) &
Это означает, что в вашем файле журнала не будет сведений о выполняемом канале, просто find_and_do_something /whatevers/in/findme_path
, но, по крайней мере, он будетработа.