Можно ли получить доступ ко всей командной строке, включая каналы, в скрипте bash?

Después del cambio

python opt/project1/Table_Control.py opt/project1/connection.yaml >> /tmp/2.log 2>&1

En el registro, encontré un error. Python no encontró el módulo de Python de solicitudes.

Cambié

python opt/project1/Table_Control.py opt/project1/connection.yaml >> /tmp/2.log 2>&1

a

/data/Anaconda2-4.4.0/envs/python36/bin/python opt/project1/Table_Control.py opt/project1/connection.yaml >> Table_Control.log >&1

p.d.

Ahora funcionó bien, PERO no entendí por qué si ejecuto desde el script de shell -sin errores,PERO si la ejecución desde el trabajo cron devolvió el error, no se encontraron solicitudes del módulo python...

8
23.07.2019, 11:40
4 ответа

Нет способа сделать это вообще .

Но интерактивная bashоболочка может использовать механизм истории и ловушку DEBUG, чтобы «информировать» команды, которые она запускает, о полной командной строке, частью которой они являются, через переменную среды:

$ trap 'export LC=$(fc -nl -0); LC=${LC#? }' DEBUG
$ sh -c 'printf "last_command={%s}\n" "$LC"' | cat; true
last_command={sh -c 'printf "last_command={%s}\n" "$LC"' | cat; true}
6
27.01.2020, 20:08

Спасибо за ответы. Я тестировал разные вещи и пришел к следующему тестовому сценарию:

test.sh:

hist=`fc -nl -0`
# remove leading and trailing whitespaces
hist="$(echo "${hist}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
echo "Command line from history: '$hist'"

if [ -t 1 ]; then
  echo "Direct output to TTY, no pipe involved."
else
  echo "No TTY, maybe a piped command."
fi

if [ -p /dev/stdout ]; then
  echo "stdout is a pipe."
else
  echo "stdout is not a pipe."
fi

readlink -e /proc/self/fd/1
rst=$?
if [ $rst -eq 0 ]; then
  echo "Readlink test status okay, no pipe involved."
else
  echo "Readlink test status error $rst, maybe a piped command."
fi

Испытания:

$./test.sh test1
Command line from history: './test.sh test1'
Direct output to TTY, no pipe involved.
stdout is not a pipe.
/dev/pts/3
Readlink test status okay, no pipe involved.

$./test.sh test2 | cat
Command line from history: './test.sh test2 | cat'
No TTY, maybe a piped command.
stdout is a pipe.
Readlink test status error 1, maybe a piped command.

$ echo "another command before pipe doesn't matter" |./test.sh test3
Command line from history: 'echo "another command before pipe doesn't matter" |./test.sh test3'
Direct output to TTY, no pipe involved.
stdout is not a pipe.
/dev/pts/3
Readlink test status okay, no pipe involved.

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

Мне не удалось подавить вывод из «readlink» (или «file», как было предложено в Archemar ), когда статус был успешным («/dev/pts/3» ). Передача вывода в /dev/null или в переменную приведет к неисправности. Так что это не вариант для меня в сценарии.

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

Редактировать :Моя заслуга mosvy, потому что вопрос был в том, как получить полную командную строку, а не только определить, находится ли скрипт на трубе. я люблю простая часть «fc -nl -0» в его ответе, потому что дальнейшая настройка системы не требуется. Это не 100-процентное решение, но это только для моего личного использования и поэтому достаточно. Спасибо всем остальным за вашу помощь.

2
27.01.2020, 20:08

Другим способом может быть доступ к автоматической переменной $BASH_COMMAND, но она по своей природе изменчива и трудно получить требуемое значение.

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

CMD="${BASH_COMMAND##* eval }" eval './test.sh arg1 | grep "xyz"'

Здесь $BASH_COMMANDрасширяется, а также очищается до evalбита строки, и результирующая строка, таким образом, "снимается" во вспомогательную переменную $CMD.

Маленький пример:

$ cat test.sh
#!/bin/sh

printf 'you are running %s\n' "$CMD"
sleep 1
echo bye bye
$
$ CMD="${BASH_COMMAND##* eval }" eval './test.sh | { grep -nH "."; }'
(standard input):1:you are running './test.sh | { grep -nH "."; }'
(standard input):2:bye bye
$

Естественно, он также может работать (на самом деле лучше )при вызове скриптов, например. sh -cили bash -c, как в:

$
$ CMD="${BASH_COMMAND}" sh -c './test.sh | { grep -nH "."; }'
(standard input):1:you are running CMD="${BASH_COMMAND}" sh -c './test.sh | { grep -nH "."; }'
(standard input):2:bye bye
$

Здесь без очистки переменной.

1
27.01.2020, 20:08

Используя /proc/self/fd, вы можете увидеть, находитесь ли вы в конвейере, а также идентификатор канала. Если вы выполните итерацию по /proc/\*/fdв поисках соответствующего канала, вы сможете найти PID другого конца канала. С PID вы можете затем прочитать /proc/$PID/cmdline, а также повторить процесс на его файловых дескрипторах, чтобы найти, во что он передан.

$ cat | cat | cat &
$ ps
  PID TTY          TIME CMD
 6942 pts/16   00:00:00 cat
 6943 pts/16   00:00:00 cat
 6944 pts/16   00:00:00 cat
 7201 pts/16   00:00:00 ps
20925 pts/16   00:00:00 bash
$ ls -l /proc/6942/fd
lrwx------. 1 tim tim 64 Jul 24 19:59 0 -> /dev/pts/16
l-wx------. 1 tim tim 64 Jul 24 19:59 1 -> 'pipe:[49581130]'
lrwx------. 1 tim tim 64 Jul 24 19:59 2 -> /dev/pts/16
$ ls -l /proc/6943/fd
lr-x------. 1 tim tim 64 Jul 24 19:59 0 -> 'pipe:[49581130]'
l-wx------. 1 tim tim 64 Jul 24 19:59 1 -> 'pipe:[49581132]'
lrwx------. 1 tim tim 64 Jul 24 19:59 2 -> /dev/pts/16
$ ls -l /proc/6944/fd
lr-x------. 1 tim tim 64 Jul 24 19:59 0 -> 'pipe:[49581132]'
lrwx------. 1 tim tim 64 Jul 24 19:59 1 -> /dev/pts/16
lrwx------. 1 tim tim 64 Jul 24 19:59 2 -> /dev/pts/16

Кроме того, если вам повезет, разные команды в конвейере получат последовательные идентификаторы PID, что немного упростит задачу.

На самом деле у меня нет сценария для этого, но я доказал концепцию.

3
27.01.2020, 20:08

Теги

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