Непосредственной проблемой в вашем коде является синтаксическая ошибка при чтении строки
if [` $x -eq 0 `]
[
и ]
должны быть отделены от аргументов внутри символом пробела. Кроме того, подстановка команды в этой строке, `$x -eq 0`
, не имеет смысла, так как она будет пытаться запустить значение $x
как команду.
У вас также есть проблемы с не -заключением в кавычки ваших расширений переменных, что лишает ваш сценарий возможности работать с именами файлов, содержащими символы пробела и шаблоны подстановки имен файлов.
Сценарий также безоговорочно затирает файл newfile
без необходимости (и завершится ошибкой, если newfile
является именем существующего каталога )и в нем отсутствует строка #!
-.
Нет смысла интерактивно запрашивать у пользователя пути к файлам. Было бы лучше, если бы пользователь мог использовать завершение имени файла оболочки в командной строке и указывать пути к файлам в виде двух операндов :
.
$./script.sh some/path/file1 some/other/path/file2
Если запустить скрипт таким образом, два пути будут доступны внутри скрипта как "$1"
и "$2"
.
Утилиту cmp
можно использовать в этом скрипте без создания временного файла. Вместо перенаправления его вывода сделайте его тихим, используя параметр -s
(для «тихого» )и используйте его статус выхода, чтобы определить, идентичны ли два файла или нет.
Скрипт будет выглядеть так
#!/bin/sh
if cmp -s -- "$1" "$2"; then
rm -i -- "$2"
fi
Или, короче,
#!/bin/sh
cmp -s -- "$1" "$2" && rm -i -- "$2"
Это вызовет rm -i
для второго из двух заданных путей, если он ссылается на файл с идентичным содержимым, что и первый путь. Параметр --
в командах cmp
и rm
необходим, чтобы избежать интерпретации имени файла, начинающегося с дефиса, как набора параметров.
Проблема с этим скриптом, как и с вашим собственным скриптом,заключается в том, что если вы дадите ему один и тот же путь дважды , т.е. вы сравните файл с самим собой, то он предложит удалить его.
Следовательно, мы также должны убедиться, что два пути относятся к двум разным файлам.
Это можно сделать, сравнив две строки имени пути друг с другом:
#!/bin/sh
if [ "$1" != "$2" ] && cmp -s -- "$1" "$2"; then
rm -i -- "$2"
fi
Этого может быть достаточно для большинства приложений, но не учитываются символические ссылки. В некоторых оболочках вы также можете использовать нестандартный --ef
тест («равный файл» ), который проверяет, относятся ли два пути к одному и тому же файлу (один и тот же i -номер узла и устройство):
#!/bin/bash
if ! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2"; then
rm -i -- "$2"
fi
или,
#!/bin/bash
! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2" && rm -i -- "$2"
И с некоторыми проверками работоспособности (также перемещение теста -ef
в раздел проверок работоспособности):
#!/bin/bash
if [ "$#" -ne 2 ]; then
# did not get exactly two arguments
printf 'Usage:\n\t%s file1 file2\n' "$0" >&2
exit 1
elif [ ! -f "$1" ] || [ ! -f "$2" ]; then
echo 'One of the files does not exist (or is not a regular file)' >&2
exit 1
elif [ "$1" -ef "$2" ]; then
printf '%s and %s refer to the same file\n' "$1" "$2" >&2
exit 1
fi
cmp -s -- "$1" "$2" && rm -i -- "$2"
Обратите внимание, что заключение расширений переменных в кавычки важно, так как имена путей нередко содержат пробелы (в macOS, это очень распространено ). Расширения переменных в двойных кавычках также предотвращают их интерпретацию как шаблоны подстановки оболочки (ваш код, например, не будет работать с файлом с именем*
). Также обратите внимание на использование строки #!
-, соответствующей сценарию.
Если ваше домашнее задание требует чтения путей к двум файлам в интерактивном режиме, сделайте это с read -r
и с IFS
, установленными в пустую строку. Это позволит вам читать пути, начинающиеся с пробелов и содержащие \
символов :
.
#!/bin/bash
IFS= read -p '1st pathname: ' -r p1
IFS= read -p '2nd pathname: ' -r p2
if [ ! -f "$p1" ] || [ ! -f "$p2" ]; then
echo 'One of the files does not exist (or is not a regular file)' >&2
exit 1
elif [ "$p1" -ef "$p2" ]; then
printf '%s and %s refer to the same file\n' "$p1" "$p2" >&2
exit 1
fi
cmp -s -- "$p1" "$p2" && rm -i -- "$p2"
Связанные:
Если вам в какой-то момент нужно проверить, пуст ли файл, как в вашем собственном коде, то не вызывайте для него wc
(это неэффективно, так как придется читать весь файл ). Вместо,используйте тест -s
:
if [ -s "$pathname" ]; then
printf '%s has non-zero size\n' "$pathname"
else
printf '%s is empty (or does not exist)\n' "$pathname"
fi
См. man test
в вашей системе или обратитесь к стандарту POSIX для этой утилиты .
ldd
перечисляет все требуемые библиотеки, включая те, которые требуются транзитивно. В метаданных RPM перечислены только прямые зависимости:
$ readelf -d /usr/bin/curl | grep NEEDED
0x0000000000000001 (NEEDED) Shared library: [libcurl.so.4]
0x0000000000000001 (NEEDED) Shared library: [libssl3.so]
0x0000000000000001 (NEEDED) Shared library: [libsmime3.so]
0x0000000000000001 (NEEDED) Shared library: [libnss3.so]
0x0000000000000001 (NEEDED) Shared library: [libnssutil3.so]
0x0000000000000001 (NEEDED) Shared library: [libplds4.so]
0x0000000000000001 (NEEDED) Shared library: [libplc4.so]
0x0000000000000001 (NEEDED) Shared library: [libnspr4.so]
0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0]
0x0000000000000001 (NEEDED) Shared library: [libdl.so.2]
0x0000000000000001 (NEEDED) Shared library: [libz.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
Приведенная выше команда выводит список библиотек, объявленных как зависимости самим двоичным файлом. Это соответствует списку зависимостей (вместе с символами версий, см. readelf -V
). Все остальные библиотеки, показанные в ldd
, являются транзитивными зависимостями.
Зависимости транзитивных библиотек отражаются в зависимостях транзитивных RPM; например, библиотеки Kerberos подтягиваются libcurl.so.4
и появляются в метаданных libcurl
.