Befehl wird über SSH nicht ausgeführt

Befehl wird über SSH nicht ausgeführt

Ich habe dieses Skript für einen Kurs erstellt. Es führt Befehle über SSH aus den Argumenten des Skripts auf einer Anzahl von Remote-Servern aus, die in einer Datei angegeben sind:

#!/bin/bash

# The server file. Can be changed with the -f argument
SERVER_FILE='/vagrant/servers'

# The function to check if the chosen SERVER_FILE exists
filecheck() {
if [[ ! -e $SERVER_FILE ]]; then
  echo "The file $SERVER_FILE does not exist." >&2
  exit 1
fi
}

# The usage statement
usage() {
  echo "usage $0 -vsn -f FILE 'COMMAND'"
  echo "  -v Verbose mode"
  echo "  -s Run command as sudo on remote server"
  echo "  -n Dry run, commands not actually executed"
  echo "  -f FILE Selects a different file other than /vagrant/servers"
  exit 1
}

# The verbose mode text things
say() {
  if [[ $VERBOSE = 'true' ]]; then
    echo "$@"
  fi
}

# The ssh command
sshing() {
  ssh -o ConnectTimeout=2 $SERVER $@
}

# User executing the command should not be root
if [[ $UID -eq 0 ]]; then
  echo "You should not execute this script with sudo or as root" >&2
  echo "Use the -s argument if you want sudo powers" >&2
  exit 1
fi

# DRYMODE is sshing by Default
DRYMODE='sshing'

#check to see if file SERVER_FILE exists
filecheck

# The options for the script
while getopts vsnf: OPTION; do
  case $OPTION in
    v)
      echo "Verbose mode on"
      VERBOSE='true'
      ;;
    s)
      say "Sudo mode"
      SUDO='sudo'
      ;;
    n)
      say "Dry run mode"
      DRYMODE='echo'
      DRYRUN='DRY RUN: '
      echo "DRY RUN MODE ON: "
      echo
      ;;
    f)
      say "Different file mode"
      SERVER_FILE=${OPTARG}
      #check to see if file SERVER_FILE exists
      filecheck
      ;;
    *)
      usage
      ;;
  esac
done

echo

# shifts so that the options are removed from the list of arguments
shift $((OPTIND-1))

#Set a variable for the rest of the arguments, as a command
COMMAND="${@}"

# Checks if the user provided any arguments apart from the optinos
if [[ $# -eq 0 ]]; then
  usage
  exit 1
fi

# Executes the commands
for SERVER in $(cat ${SERVER_FILE}); do
  say "Executing ${COMMAND} on ${SERVER}:"
  $DRYMODE $DRYRUN $SUDO ${COMMAND} 2> /dev/null
  CMDEX=$?
  # if the exit status is 255, something is wrong with the server or is unreachable
  if [[ $CMDEX -eq 255 ]]; then
    echo "The server you're trying to reach does not exist or is unreachable. Aborting." >&2
    exit 1
  fi
  # if the exit status is non 0 and non 255, something is wrong with the command
  if [[ $CMDEX -ne 0 ]]; then
    echo "Invalid command ${COMMAND} or wrong syntax. Aborting." >&2
    exit 1
    # if the exit status is non 0 and non 255, something is wrong with the command
  fi
  say "Command ${COMMAND} executed successfuly."
done
exit 0

Und es funktioniert perfekt für einfache Befehle (wie ls, psund sogar adduser test), aber es bricht einfach ab, wenn ich ihm einen Befehl gebe, der ein Anführungszeichen enthält, AUSSER ich setze den ganzen Befehl in einfache Anführungszeichen.

Ich weiß nicht, ob es ein Fehler in meinem Code oder so ist, aber ich kann hierdurch keine Befehle weiterleiten.

Dieser Befehl funktioniert also nicht:

[vagrant@admin01 vagrant]$ ./run-everywhere.sh -sv 'echo 1 | passwd --stdin test4'

Wenn ich das Pipe-Zeichen mit \| abtrenne, wird es einfach wörtlich als \| geschrieben. Dieser andere Befehl funktioniert auch nicht:

[vagrant@admin01 vagrant]$ ./run-everywhere.sh -sv 'echo "1" | sha256sum > file1'

BEARBEITEN:

Ich habe das Problem mit dem nicht funktionierenden Piping festgestellt: Ich muss auch NACH dem Pipe-Befehl sudo schreiben, wenn ein Befehl sudo-Berechtigungen benötigt. Das hier funktioniert folgendermaßen:

[vagrant@admin01 vagrant]$ ./run-everywhere.sh -sv 'echo 1 | sudo passwd --stdin test4'

Ich kann jedoch immer noch nicht umleiten.

Antwort1

Versuche dies:

sshing () {
  ssh -o ConnectTimeout=2 "$SERVER" "$@"
  # ................................^..^ crucial quotes
}
# ...
cmd="$*"
# ...
while read -r SERVER; do
  say "Executing ${COMMAND} on ${SERVER}:"
  $DRYMODE $DRYRUN $SUDO sh -c "${COMMAND}" 2> /dev/null
  # .....................11111.2..........2
  # 1. run with a shell to enable redirections and pipe
  # 2. crucial quotes
  # ...
done < "$SERVER_FILE"

Wenn Sie den Befehl in einer Shell mit „sudo“ ausführen, kann die gesamte Pipeline mit erhöhten Berechtigungen ausgeführt werden.

Außerdem sollten Sie sich die Verwendung von Variablennamen in GROSSBUCHSTABEN abgewöhnen. Eines Tages werden Sie versehentlich PATH überschreiben und sich dann wundern, warum Ihr Skript nicht funktioniert.

Antwort2

Habe das Problem gefunden. Wenn ich das Skript mit Sudo-Berechtigungen ausführte, um einige Dateien selbst zu berühren, wurden die Dateien unter dem Namen und der Gruppe von Root erstellt, was bedeutete, dass ich keine Berechtigungen für diese Datei hatte.

verwandte Informationen