Для задания меня просят умно написать функцию bash, которая имеет те же основные функции, что и функция cp
(копия). Нужно только скопировать один файл в другой, поэтому несколько файлов не будут скопированы в новый каталог.
Поскольку я новичок в языке bash, я не могу понять, почему моя программа не работает. Оригинальная функция просит перезаписать файл, если он уже существует, поэтому я попытался реализовать это. Это не удается.
Кажется, что файл завершается с ошибкой в несколько строк, но, что наиболее важно, при условии, что он проверяет, существует ли уже файл для копирования ( [-e "$2"]
). Несмотря на это, он по-прежнему показывает сообщение, которое должно быть запущено, если это условие выполняется (имя файла ...).
Может ли кто-нибудь помочь мне исправить этот файл, возможно, предоставив некоторую полезную информацию о моем базовом понимании языка? Код выглядит следующим образом.
#!/bin/sh
echo "file variable: $2"
if [-e file]&> /dev/null
then
echo "The file name already exists, want to overwrite? (yes/no)"
read | tr "[A-Z]" "[a-z]"
if [$REPLY -eq "yes"] ; then
rm "$2"
echo $2 > "$2"
exit 0
else
exit 1
fi
else
cat $1 | $2
exit 0
fi
[ ... ] &> /dev/null
. Поддерживаемые тесты[ ... ]
всегда молчат, только в случае синтаксических ошибок выдается любой вывод. Глушить такой тест - это просто копать собственную могилу.cat $1 | $2
« направляет » вывод первой команды к команде из второй переменной. Но это имя файла, а не имя команды для выполнения.[
команды в вашемif
.|
в файл и перенаправлением в файл с помощью>
. Это основные проблемы синтаксиса, которые уже должны были быть рассмотрены в вашем классе.Ответы:
cp
Утилита счастливо перезаписывать целевой файл , если этот файл уже существует, без запроса пользователя.Функция, которая реализует основные
cp
возможности, без использованияcp
будетЕсли вы хотите попросить пользователя перед перезаписью цели (обратите внимание, что это может быть нежелательно, если функция вызывается неинтерактивной оболочкой):
Диагностические сообщения должны идти в стандартный поток ошибок. Это то, что я делаю
printf ... >&2
.Обратите внимание, что нам на самом деле не нужен
rm
целевой файл, поскольку перенаправление будет его урезать. Если бы мы сначала захотелиrm
, то вам нужно было бы проверить, является ли это каталогом, и если это так, вместо этого поместите целевой файл в этот каталог, как это иcp
будет сделано. Это делает это, но все еще без явногоrm
:Возможно, вы также захотите убедиться, что источник действительно существует, что
cp
делает что-то (cat
делает это тоже, поэтому, конечно, его можно полностью исключить, но при этом будет создан пустой целевой файл):Эта функция не использует "bashisms" и должна работать во всех
sh
подобных оболочках.Немного больше настроек для поддержки нескольких исходных файлов и
-i
флаг, который активирует интерактивные подсказки при перезаписи существующего файла:В вашем коде плохие интервалы
if [ ... ]
(нужно пространство до и после[
, и до]
). Вы также не должны пытаться перенаправить тест,/dev/null
поскольку сам тест не имеет выходных данных. Кроме того, первый тест должен использовать позиционный параметр$2
, а не строкуfile
.Используя,
case ... esac
как я, вы избежите необходимости использовать строчные / прописные буквы ответа пользователяtr
. Вbash
, если бы вы хотели сделать это в любом случае, более дешевым способом сделать это был бы использованиеREPLY="${REPLY^^}"
(для верхнего регистра) илиREPLY="${REPLY,,}"
(для lowercasing).Если пользователь говорит «да» с вашим кодом, функция помещает имя файла целевого файла в целевой файл. Это не копирование исходного файла. Это должно провалиться до фактического бита копирования функции.
Бит копирования - это то, что вы реализовали с помощью конвейера. Конвейер используется для передачи данных с выхода одной команды на вход другой команды. Это не то, что нам нужно делать здесь. Просто вызовите
cat
исходный файл и перенаправьте его вывод в целевой файл.То же самое не так с твоим призывом
tr
ранее.read
будет устанавливать значение переменной, но не будет выводить данные, такread
что передача чего-либо не имеет смысла.Никакого явного выхода не требуется, если пользователь не говорит «нет» (или функция сталкивается с некоторым условием ошибки, как в битах моего кода, но так как это функция, которую я использую,
return
а неexit
).Кроме того, вы сказали «функция», но ваша реализация представляет собой скрипт.
Загляните на https://www.shellcheck.net/ , это хороший инструмент для выявления проблемных фрагментов скриптов оболочки.
Использование
cat
- это только один из способов скопировать содержимое файла. Другие способы включаютdd if="$1" of="$2" 2>/dev/null
sed "" "$1" >"2"
илиawk '1' "$1" >"$2"
илиtr '.' '.' <"$1" >"$2"
и т. Д.Сложность заключается в том, чтобы заставить функцию копировать метаданные (владение и разрешения) из источника в цель.
Еще одна вещь, на которую следует обратить внимание: написанная мной функция будет вести себя совсем не так, как
cp
если бы целью было что-то вроде,/dev/tty
например (нестандартный файл).источник
cat "$1" >"$2"
будет работать в 2 раза: оболочка сначала увидит> "$2"
, что означает: create-or-clobber (= empty) файл "$ 2" и перенаправить стандартный вывод команды в этот файл. Затем он запускает команду:cat "$1"
и перенаправляет свой стандартный вывод в файл"$2"
(уже пустой или созданный пустой).-ef
сравнении файлов иlocal -a
.-ef
принимает уведомления, если два файла совпадают (также заботится о ссылках) иlocal -a
создает переменную локального массива.