rm работает в командной строке, но не в скрипте

Для SD-карты, которая будет использоваться для дополнительного пространства, я не знаю, можно ли это сделать, но по нескольким причинам я считаю, что это не рекомендуется. Специально, если слот SD поврежден / старый, SD-карта повреждена (поскольку это портативное мультимедийное устройство), и, скорее всего, загрузочная часть не распознает SD в некоторых случаях, поэтому он не будет загружаться оттуда. вы также не можете разделить систему на одну небольшую часть внутреннего жесткого диска, а остальную часть на SD.

Теперь для рекомендаций. Я настоятельно рекомендую начать удаление файлов с жесткого диска 4 ГБ. С 100 МБ вы не сможете установить почти ничего (может быть, Damn Small Linux), но не Ubuntu / Lubuntu /? Buntu. В любом случае обновление не позволяет это сообщение, потому что у вас есть 100 МБ, и ему требуется 1.7 Free. Если вы проверите размеры, вы заметите, что дополнительный размер, который он упоминает, на 100 МБ меньше, чем тот, который ему нужен. Поэтому он говорит, что вам нужно освободить AT LEAST 1,6 ГБ с жесткого диска 4 ГБ, чтобы установить его.

1
задан 11 September 2016 в 16:07

2 ответа

В вашем скрипте есть различные возможные точки отказа. Прежде всего, rm *.old* будет использовать globbing для создания списка всех совпадающих файлов и может иметь дело с именами файлов, содержащими пробельные символы. Однако ваш скрипт присваивает переменную каждому результату glob и делает это без кавычек. Это сломается, если ваши имена файлов содержат пробелы. Например:

$ ls
'file name with spaces.old.txt'  file.old.txt
$ rm *.old.*   ## works: both files are deleted

$ touch "file.old.txt" "file name with spaces.old.txt"
$ for i in ./*; do oldfile=$i; rm -v $oldfile; done
rm: cannot remove './file': No such file or directory
rm: cannot remove 'name': No such file or directory
rm: cannot remove 'with': No such file or directory
rm: cannot remove 'spaces.old.txt': No such file or directory
removed './file.old.txt'

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

$ for i in ./*; do oldfile="$i"; rm -v "$oldfile"; done
removed './file name with spaces.old.txt'
removed './file.old.txt'

То же самое относится к почти любому использованию $i в вашем скрипте. Вы должны globbing .

Следующая возможная проблема заключается в том, что вы, кажется, ожидаете, что *.old.* соответствует файлам с расширением .old. Это не так. Он соответствует «0 или более символов» (*), затем ., затем «старый», затем другой ., а затем «0 или более символов снова». Это означает, что он не будет соответствовать чему-то вроде file.old, но только что-то вроде `file.old.foo:

$ ls
file.old  file.old.foo
$ for i in *; do if [[ "$i" == *.old.* ]]; then echo $i; fi; done
file.old.foo     

Итак, нет совпадающего foe file.old. В любом случае ваш скрипт намного сложнее, чем необходимо. Попробуйте это вместо:

#!/bin/bash

for i in *; do
    if [[ -f "$i" ]];  then
        if [[ "$i"  ==  *.old ]]; then
            rm -v "$i" || echo "rm failed for $i"
        else
            echo "$i doesn't have an .old extension"
        fi
        cp -v "$i" "$i".old
    else
        echo "$i is not a file"
    fi 
done

Обратите внимание, что я добавил -v в выражения rm и cp which does the same thing as what you were doing with your echo`.

Это не идеально, поскольку, когда вы обнаружите, например, file.old, это будет удалено, а позже скрипт попытается скопировать его и сбой, поскольку файл больше не существует. Однако вы не объяснили, что вы на самом деле пытаетесь сделать сценарий, я не могу исправить это для вас, если вы не сообщите нам, что вы на самом деле пытаетесь выполнить.

Если вы хотите: i) удалить все файлы с расширением .old и ii) добавить расширение .old в любые существующие файлы, которые его не имеют, все, что вам действительно нужно:

#!/bin/bash

for i in *.old; do
    if [[ -f "$i" ]]; then
        rm -v "$i" || echo "rm failed for $i"
    else
        echo "$i is not a file"
    fi 
done
## All the ,old files have been removed at this point
## copy the rest
for i in *; do
    if [[ -f "$i" ]]; then
        ## the -v makes cp report copied files
        cp -v "$i" "$i".old
    fi
done
13
ответ дан 23 May 2018 в 06:15
  • 1
    Я пытаюсь сделать резервные копии файлов в file.old, но в то же время rm любые файлы, которые заканчиваются на .old.old или .old.old.old или .old.old.old и т. Д. На командной строке я использую rm *.old.*, который удаляет эти файлы, но не файл резервной копии file.old. Я пытаюсь сделать это в своем сценарии. благодаря – Don 11 September 2016 в 18:39
  • 2
    @Don, пожалуйста, отредактируйте свой вопрос и объясните это более подробно. Добавьте имена файлов примеров и то, что вы хотели бы сделать с ними после запуска вашего сценария. В идеале заходите в chat и пишите мне, чтобы мы могли обсудить это. – terdon♦ 11 September 2016 в 18:55

Единственными случаями rm $oldfile могут быть ошибки, когда ваше имя файла содержит любой символ IFS (пробел, табуляция, новая строка) или любой символ глоба (*, ?, []). [!d0 ]

Если присутствует какой-либо символ из IFS, оболочка будет выполнять разбиение слов и на основе наличия расширений имени шаблонов глобусов при расширении переменной.

Так, например, если имя файла foo bar.old., переменная oldfile будет содержать foo bar.old..

Когда вы это делаете:

rm $oldfile

оболочка сначала разбивает разложение oldfile на пробел на два слова, foo и bar.old.. Таким образом, команда становится:

rm foo bar.old.

, что, очевидно, приведет к неожиданному результату. Кстати, если у вас есть какие-либо операторы globbing (*, ?, []) в расширении, то расширение пути также будет выполнено.

Вам нужно процитировать переменные, чтобы получить желаемый результат:

rm "$oldfile"

Теперь не будет разбито слово или расширение пути, поэтому вы должны получить желаемый результат, то есть желаемый файл будет удален. Если какое-либо имя файла начинается с -, тогда выполните:

rm -- "$oldfile"

Вы можете спросить, почему нам не нужно указывать переменные при использовании внутри [[ , причина в том, что [[ является ключевым словом bash и обрабатывает переменное расширение, внутренне сохраняющее литерал расширения.

Теперь пару точек:

[d12 ] Вы должны перенаправить STDERR (exec 2>errorfile) перед командой rm, иначе [[ -s errorfile ]] тест даст ложные срабатывания. Вы использовали [ -s $errorfile ], вы используете переменное расширение $errorfile, которое было бы присвоено NUL errorfile переменная не определена нигде. Возможно, вы имели в виду только [ -s errorfile ], на основе перенаправления STDERR. Если переменная errorfile определена при использовании [ -s $errorfile ], она снова захлестнет вышеупомянутые случаи IFS и заглохнет, поскольку в отличие от [[, [ f35] не обрабатывается внутри bash. В более поздней части скрипта вы пытаетесь cp уже удаленный файл (опять же без цитирования переменной), это не имеет никакого смысла, вы должны проверить, что патрон и внести необходимые исправления на основе вашей цели.
7
ответ дан 23 May 2018 в 06:15

Другие вопросы по тегам:

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