Удалите все в каталоге, кроме одного файла, с помощью SSH

#bash #ssh #escaping #rm

Вопрос:

В BASH следующая команда удаляет все в каталоге, кроме одного файла:

 rm -rf !(filename.txt)
 

Однако в SSH та же команда ничего не меняет в каталоге и возвращает следующую ошибку: -jailshell: !: событие не найдено

Итак, я сбежал ! с помощью (скобки также требуют побега), но это все еще не работает:

 rm -rf !(filename.txt)
 

Он не возвращает никаких ошибок, и в каталоге ничего не изменилось.

Возможно ли вообще выполнить эту команду в SSH? Я нашел обходной путь, но если это возможно, это значительно ускорит процесс.

Я подключаюсь к серверу ssh, используя псевдоним ниже:

 alias devssh="ssh -p 2222 -i ~/.ssh/private_key user@host"
 

Комментарии:

1. Пожалуйста, добавьте свою команду ssh к вашему вопросу (без комментариев).

2. @Сайрус, это там. Это второй кодовый блок.

3. Я думаю, что Сайрус имел в виду полную ssh команду (т. Е. ssh user@host ... ), а не только команду, которая выполняется внутри ssh.

4. Откуда это -jailshell: берется?

5. @Cyrus, он возвращается в окне терминала.

Ответ №1:

!(filename.txt) это extglob, будущее bash, которое, возможно, придется включить. Убедитесь, что ваш ssh-сервер работает под управлением bash и что extglob включен:

 ssh user@host "bash -O extglob -c 'rm -rf !(filename.txt)'"
 

Или используя свой псевдоним:

 devssh "bash -O extglob -c 'rm -rf !(filename.txt)'"
 

Если вы уверены, что удаленная система использует bash по умолчанию, вы также можете удалить эту bash -c деталь. Но ваше сообщение об ошибке указывает на то, что сервер ssh запущен jailshell .

 ssh user@host 'shopt -s extglob; rm -rf !(filename.txt)'
devssh 'shopt -s extglob; rm -rf !(filename.txt)'
 

Комментарии:

1. Я попытался установить extglob с помощью bash -O extglob -c 'rm -rf !(filename.txt) , и он уничтожил все содержимое во всем каталоге public_html.

2. Кажется, все было бы правильно, если бы filename.txt в этом каталоге ничего не было. Вы уверены, что такой файл был там раньше?

3. @Thomas: Я предлагаю заменить rm на echo rm первый.

4. Вот локальный тест , показывающий, что команда работает должным образом.

5. Я просто буду очень рад, что это сервер разработчиков.

Ответ №2:

Я бы так не поступил. Я бы не стал полагаться на то, что баш находится на пульте дистанционного управления, и я бы не стал полагаться ни на какие башизмы. Я бы использовал:

 $ ssh user@host 'rm $(ls | grep -v "^filename.txt$")'
 

Если бы я хотел защититься от возможности того, что каталог может быть пустым, я бы назначил вывод $(...) переменной и проверил его на пустоту. Если бы я был обеспокоен тем, что команда может оказаться слишком длинной, я бы записал имена в файл и отправил вывод grep в rm с помощью xargs.

Если бы это было слишком сложно, я бы скопировал сценарий на пульт дистанционного управления и выполнил его.

Комментарии:

1. Я был бы обеспокоен не только длительным командованием. Если бы у вас были файлы important.txt not important.txt и вы побежали rm $(ls | grep -v "^important.txt$") , то вас ждал бы сюрприз .

2. ls , записанный в канал, создает одну строку на имя. ^important.txt$ совпадает со всей линией, закрепленной спереди рядом ^ . Он не совпадает not important.txt , что grep -v приведет к печати, потому что смысл перевернут.

3. Да, все это правильно. Но вы пробовали это сами (см. Ссылку в моем предыдущем комментарии). Проблема в том, что без кавычек $() происходит разделение слов . not important.txt затем превращается в not и. important.txt Кроме того, глобусы в именах файлов будут расширяться.

4. @Socowi, спасибо, теперь я понимаю вашу точку зрения. Я бы все равно последовал своему совету, чтобы использовать стандартный синтаксис, и вашему, чтобы тщательно протестировать, особенно с **rm**(1).