Почему мой Bash-скрипт отображает ошибку "слишком много аргументов" в команде cp?

5209
Mike

Вот мой сценарий, я получаю сообщение об ошибке «строка 33: [: слишком много аргументов», я запутался, почему, конечно, только 2 аргумента предоставляются здесь cp?

Я предоставляю в каталог две директории без пробелов, т.е. $ 1 = dir1 / и $ 2 = dir2 /

#!/bin/bash  ### Assign suitable names to arguements. ###  source=$1 dest=$2  ### Error handler for all script errors. ###  function errorHandler { case $1 in ERRargs) printf "USAGE: e2backup source_dir dest_dir.\n"; exit 1;; ERRsource) printf "ERROR: Source does not exist or is not a directory.\n"; exit 2;; ERRdest) printf "ERROR: Destination does not exist or is not a directory.\n"; exit 3;; ERRempty) printf "ERROR: Destination is not empty.\n"; exit 4;; esac }  ### Test num. of args, source/dest validity and empty dest. Then perform backup. ###  if [ $# -ne 2 ] then errorHandler ERRargs elif [ ! -d $source ] then errorHandler ERRsource elif [ ! -d $dest ] then errorHandler ERRdest elif [ -n "$(ls -A $dest)" ]  then errorHandler ERRempty elif [ cp -R $source $dest ] then printf "Successfully backed-up from $source to $dest"; exit else printf "Back-up failed, please see e2backup.error"; exit 5 fi 
0

2 ответа на вопрос

1
Alex P.

Это не cpтолько [ака, testкоторый дает ошибку

И как я могу смягчить эту проблему? Я хочу использовать статус возврата для elif, но при этом выполнить cp одновременно ... Mike 11 лет назад 0
Допустим, вы хотите сохранить этот вид плохого кодирования (на мой взгляд) ... В качестве выходного кода вы должны иметь код возврата: `elif $ (cp -R" $ source "" $ destination "; printf"% d " "$?"); затем` 11 лет назад 2
elif проверяет статус возврата следующей команды. Обычно это команда `[`, псевдоним для `test`. Если вы хотите перейти на возвращаемый статус `cp`, просто напишите` elif cp -R $ source $ dest`. garyjohn 11 лет назад 2
+1 Гэри, его версия тоже верна. Я думал, что по-своему, где я всегда отделяю команды и коды выхода из тестов. 11 лет назад 0
Хороший парень. И почему на ваш взгляд это плохое кодирование? Любые советы будут оценены. Mike 11 лет назад 0
Что ж, лучше запускать команды отдельно от тестов, поэтому отладка проще. Вы точно знаете, как в вашем примере, это не проблема cp, а проблема оператора if (то же самое относится к `ls -A $ dest`, который у вас есть); Кроме того, вы можете иметь как код выхода, так и вывод, чтобы вы могли распечатать вывод и для дальнейшей отладки. Кроме того, хорошо, чтобы любой строковый параметр был заключен в двойные кавычки, поэтому, если в нем есть пробел, bash не подумает, что у вас есть несколько параметров вместо одного для этой строки. 11 лет назад 0
Кроме того, даже если мне нравится, что вы используете printf, а не echo, который не является POSIX, вы используете его не лучшим образом. Если в вашем $ source и $ dest есть какие-то специальные символы, такие как%, printf попытается расширить его, потому что первый параметр для printf расширит элементы форматирования, такие как% d,% s,% .2f. Таким образом, лучший способ сделать это состоит в том, чтобы все переменные были отдельными параметрами печати. В вашем примере: `printf" Успешное резервное копирование из "% s" в "% s". " "$ source" "$ dest" # простые кавычки только для эстетики, поэтому легче узнать, где закончилось значение` 11 лет назад 0
Хорошо сладкий, ура Раду. Mike 11 лет назад 0
Кроме того, нет ничего плохого в том, чтобы переходить на новую строку, но это не дает вам никаких преимуществ, только новые строки в вашем коде. Вы можете просто написать `if ...; затем` 11 лет назад 0
0
Huygens

To the point, the statement cp -R $source $dest is not a test condition in itself. So you should tell BASH to execute the cp commands. You can either use the back-quote or $(...) and test against the result or better as suggested by one commenter:

if [[ $# -ne 2 ]] then errorHandler ERRargs elif [[ ! -d $source ]] then errorHandler ERRsource elif [[ ! -d $dest ]] then errorHandler ERRdest elif [[ -n "$(ls -A $dest)" ]] then errorHandler ERRempty elif cp -R $source $dest then printf "Successfully backed-up from $source to $dest"; exit else printf "Back-up failed, please see e2backup.error"; exit 5 fi 

Updated: BASH supports both '[]' and '[[]]' for a test. There is a slightly different meaning that the curious one can find in the man page. In addition, one could also use other ways to do a test, like using the test bash builtin command.

Ваш отзыв неверен. [] эквивалентно тесту. [[]] - это новое соединение, появившееся в bash, поскольку в некоторых версиях я не помню, что расширяет функциональность теста сопоставлением с шаблоном. Несмотря на то, что это очень полезная функция, это соединение не является POSIX, что в некоторых случаях может быть нежелательным, например, когда вы хотите, чтобы ваш сценарий был распределен по различным оболочкам. 11 лет назад 0
На Radoo спасибо поправлю ответ. Однако, поскольку это bash-скрипт (первая строка `#! / Bin / bash`), '[[]]' будет работать на любой платформе, которая поддерживает Bash. Даже когда я пытался сделать скрипт как можно более независимым от конкретной оболочки, мне никогда не удавалось сделать его переносимым без модификации, скажем, от BASH до KSH. Huygens 11 лет назад 0
Нет смысла записывать стандартный вывод `cp`, поскольку он обычно не производит ничего. Просто используйте `elif cp -R" $ source "" $ dest "` для проверки состояния выхода `cp`. chepner 11 лет назад 0
@chepner Я не уверен, что я ел в тот день, должно быть, это было довольно плохо ;-) Я исправил это еще раз и даже сделал эту публикацию вики-сообществом, так как мой первоначальный ответ довольно далек от того, что было написано благодаря Radoo и вы! Huygens 11 лет назад 0

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