Заставьте CP возвратить ошибочное значение, если цель существует

Вы могли использовать функцию в ударе (или любая оболочка POSIX) как это:

grep() { 
    if [ -t 1 ] && [ -t 0 ]; then 
        command grep -n "$@"
    else 
        command grep "$@"
    fi
}

[ -t 1 ] часть использует [ команда (также известный как test) проверять, связан ли stdout с tty.

[ -t 0 ] вход стандарта проверок, также, так как Вы указали, чтобы только добавить номера строки если grep единственная команда в конвейере.

6
14.11.2012, 03:29
4 ответа

Вы могли сделать:

(set -C &&  cat < /path/to/src > /path/to/dest)

Это ничего не скопирует кроме содержания файла хотя (не полномочия, владение или разреженность как некоторые cp реализации делают).

1
27.01.2020, 20:24

Некоторые cp реализации, включая GNU cp, имейте нестандартное -n переключитесь для не избиения файла, если он существует. но GNU cp возвраты 0 так или иначе.

Вы могли использовать, если оператор в Вашем сценарии оболочки для тестирования существования файла перед копированием чего-то в него:

if [ -e /path/to/file ]
  then 
   exit 1
  else
   cp file /path/to/file
fi

или если Вы хотите функцию, Вы могли бы использовать что-то вроде этого:

function cpa(){ 
 if [ -e "$2" ]
  then 
   exit 1
  else 
   /bin/cp "$1" "$2"
  fi 
}
6
27.01.2020, 20:24
  • 1
    Это "не возвращает ненулевое значение в случае, если конечный файл действительно уже существует", который является тем, для чего OP, который попросили относительно, и это не является замена cp... –  Chris Down 14.11.2012, 04:22
  • 2
    @ChrisDown он попросил альтернативу для сценариев оболочки. Который является тем, что я обеспечил –  h3rrmiller 14.11.2012, 04:29
  • 3
    я на самом деле решил свое текущее возникновение таким образом, спасибо. Функция должна лучше использовать return вместо exit. То, что волнует меня, является отсутствием атомарности, т.е. могли бы быть условия состязания, где некоторый другой процесс создает файл между этим сценарием, делающим проверку и этим делающий копию. –  MvG 14.11.2012, 09:04
  • 4
    Вы хотите [ -e "$file" ] || [ -L "$file" ] если Вы хотите рассмотреть символьные ссылки на несуществующие/недоступные файлы. И обратите внимание, что существует потенциал для состояния состязания там. –  Stéphane Chazelas 14.11.2012, 11:48
  • 5
    Просто думая вслух о том, как избежать состояния состязания. Если цель существует, сбой рано. Еще скопируйте файл в некоторое reserved-for-current-process местоположение в той же файловой системе как желаемая цель. Получите inode этого tempfile. Сделайте a mv -n tempfile target. Проверьте это inode target соответствует тому, который Вы читаете из tempfile, еще приводите к сбою. Предложенные улучшения? –  dubiousjim 14.11.2012, 13:26

Следующий отрывок оболочки копирует файл, только если цель не существует и возвращает ненулевое состояние, если цель существует.

(set -C; : >"$target" && cp -- "$source" "$target")

Это не является атомарным: если файл создается после попытки ударить $target и прежде чем копия запускается, она будет перезаписана. Кроме того, cp не является атомарным: другой процесс может наблюдать записанный файл. Это действительно, однако, работает правильно, если все параллельные писатели используют ту же стратегию.

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

( set -C
  tmp=$(mktemp -p "$(dirname -- "$target")")
  cp -- '$source" "$tmp"
  if : >"$target"; then
    mv -i -- "$tmp" "$target"
  else
    rm -- "$tmp"
    false
  fi
)
3
27.01.2020, 20:24

Подробно останавливаясь на моем комментарии к ответу h3rrmiller, и после шаблона отрывка Gilles, вот другой метод создания временной копии, затем перемещая его в место. Я полагаю, что этот метод не уязвим ни для каких условий состязания. Это действительно требует -n флаг на mv, который не является частью спецификации POSIX. Однако это, действительно кажется, широко доступно. (Проверенный на реализации GNU, также BusyBox, FreeBSD, OS X.)

(
  tmp=$(mktemp "${target}.XXXXXX") && # "mktemp -p" doesn't work on BSD
  cp -- "$source" "$tmp" && # you may want to add -p flag
  inode=$(ls -di "$tmp" | cut -d' ' -f1) && # see comment below
  mv -n -- "$tmp" "$target" && # won't overwrite, but doesn't then exit non-0
  if [ "$(ls -di "$target" | cut -d' ' -f1)" != "$inode" ]; then
    rm -- "$tmp"; false
  fi
)

В Linux можно получить использование inode stat -c'%i' "$tmp", но это не портативно.

Вместо того, чтобы проверить inode, другая идея состояла бы в том, чтобы проверить, существует ли файл все еще в пути $tmp. Если mv -n ... следовавший затем не должен быть. (Если некоторый другой процесс недавно не создал $tmp перед проверкой, чтобы видеть, отсутствовало ли это.)

Для эффективности имело бы смысл добавлять проверку если $target существует в начале стандартной программы. Если мы видим, что это действительно существует, мы можем сразу перестать работать, вместо того, чтобы делать копию, пытаясь переместить его, то, видя, что это перестало работать настолько удаляющий копию. Это оставляют как (легкое) осуществление.

1
27.01.2020, 20:24

Теги

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