Команда поиска SSH не распознает каталог, хранящийся в локальной переменной

@steeldriver дал более красноречивый ответ (говорят, что мы используем GNU version of sortи хотели бы учитывать первые 6 знаков после запятой):

sort -g -k 3.1,3.6 -k 2.1,2.6  sortedExample

что приводит к:

0 0.2401209140718633 0.02243994752564071
0 0.2667328325084663 0.02243994752564071
0 1.86630577374265 0.02243994752564048

На основании этого ответа:

Сначала мы обрезаем (скажем до 6-го знака после запятой )2-й и 3-й столбцы со следующими (На данный момент это было применено дважды для каждого столбца, я отредактирую свой ответ в курсе времени):

sed 's|\([0-9]\.[0-9]\{6\}\)[0-9]\{1,\}|\1|' example > interim

Затем вышеупомянутая команда:

sort -g -k 3,3 -k 2,2  sortedExample

Желаемый результат получается как:

0 0.240120 0.022439
0 0.266732 0.022439
0 1.866305 0.022439

1
01.04.2020, 17:01
2 ответа

Попробуйте это:

ssh "$user@$ip" "out_dir=$out_dir;" '
    discard=$( find $out_dir -exec basename {} \; | head -n -1 )
    for f in $discard; do
        echo "rm $f"
    done
'

Примечание.:Предполагаемую дистанционную команду можно было бы сделать проще и безопаснее, но придираться к этому можно только запутаться.

По сути, вы должны передать части, которые a)должны также быть расширены на локальной машине, а те, которые b)должны быть только можно расширить на удаленной машине как отдельные аргументы для ssh, первый из которых заключен в двойные -, а второй — в одиночные -.

Ssh соединит все «командные» аргументы пробелами, прежде чем передать их как один аргумент в параметр -cоболочки входа пользователя на удаленном компьютере.

Если удаленная команда сама должна содержать одинарные кавычки, вы можете использовать комбинацию подстановки команд + здесь doc. Также, если значение локальной переменной может содержать пробелы и другие специальные символы,вам следует избегать их:

out_dir='/path/to/ * happiness * '
out_dir=$(printf %s "$out_dir" | sed 's/[^a-zA-Z0-9_/.]/\\&/g')
ssh localhost out_dir="$out_dir;" "$(cat <<'EOT'
  echo '<$out_dir>' = "<$out_dir>"
EOT
)"

Обратите внимание, что одинарные кавычки в <<'EOF'; если опущено, $out_dirв этом документе будет развернуто (на локальном компьютере ).

Последние версии bash имеют форму ${var@Q}, так что вы можете просто использовать "out_dir=${outdir@Q};"вместо уродливого echo | sed.

Передача удаленного сценария через stdin редко (если вообще когда-либо! )необходимо.

0
19.03.2021, 02:30

Причина, по которой вы получаете сообщение «Нет такого файла или каталога» при попытке #1, заключается в том, что интерполяция всех переменных и команд для heredoc (и<<EOF)выполняется локально перед отправкой в удаленный узел.

Как вы правильно заметили, $out_dirинтерполируется; вы видите каталог, который хотите видеть. Это происходит на вашем локальном компьютере до того, как вы сделаете вызов ssh. Подстановка команд($())также происходит локально (, но вы собираетесь делать это удаленно ). Иными словами, вся находка обрабатывается локально, прежде чем она будет отправлена ​​на удаленную машину --, все, что упаковано в $(), обрабатывается heredoc. Таким образом, похоже ${out_dir}отсутствует на вашем локальном компьютере --«Нет такого файла или каталога».

Если вы хотите увидеть это лучше, давайте упростим пример. Попробуйте это:

$ ssh foo@localhost <<EOF
  echo "using account: $(whoami)"
EOF                            
Pseudo-terminal will not be allocated because stdin is not a terminal.
<truncated>
using account: vagrant

Очевидно, что содержимое $ ()выполняется локально, так как моя локальная учетная запись «бродячая»; при правильной работе учетная запись была бы «foo», потому что я указал ssh foo@localhost.

Попытка #2 не работает, потому что вы экранировали '\' (, а не ';' ). Поиск потребностей -execпрекращен, а сейчас его нет. Вместо этого команда резко заканчивается, и у вас есть оборванный ';' который завершает команду bash. '|' ожидает пересылки некоторого ввода, но ничего не указано. По сути, вы создали это:

$ | cat
-bash: syntax error near unexpected token `|'

Итак, какое рабочее решение?

Что ж, findможет удалить за вас:

ssh $user@$ip <<EOF
  find $out_dir -delete
EOF

Это просто и прямо. Если вы беспокоитесь о выборе одних файлов и исключении других, пересмотрите find.

Я даю совет «пересмотреть find», потому что в вашей текущей версии похоже, что вы пытаетесь выполнить некоторую обработку крайних случаев:

  • использование базового имени
  • использованиеhead -n -1

Но я не ожидаю, что эта обработка будет работать так, как вы предполагаете.

Во-первых, вызов basenameприведет к удалению большей части пути, и в вашей команде ssh вы ничего не делаете для изменения каталога. Ваше выполнение ssh попытается удалить все, что относится к домашнему каталогу ${user} --, и при указании ${out _dir} вы, похоже, хотите использовать каталог, отличный от домашнего! Опять же, просто позвольте findсделать удаление за вас.

Во-вторых, и я могу ошибаться в этом, но я подозреваю, что вы используете head -n -1, чтобы избавиться от ${out _dir} из вашего списка целевых файлов.

$ find junk/
junk/
junk/one
junk/two
junk/three

Правильно, вы не хотите удалять junk/.

Однако попробуйте вот это:

$ seq 1 4
1
2
3
4
$ seq 1 4 | head -n -1
1
2
3

Это не сохраняет первую строку, но сохраняет последнюю. Попробуйте хвост:

$ seq 1 4 | tail -n +2
2
3
4

Но опять же, пусть findсделает удаление за вас.

Если вам нужно найти только для удаления файлов, посмотрите на -type f. Но есть также шаблоны исключения и включения для более сложной фильтрации.

1
19.03.2021, 02:30

Теги

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