@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
Попробуйте это:
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 редко (если вообще когда-либо! )необходимо.
Причина, по которой вы получаете сообщение «Нет такого файла или каталога» при попытке #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
. Но есть также шаблоны исключения и включения для более сложной фильтрации.