Как проверить, существует ли несколько файлов?

У меня есть сценарий оболочки, который ищет файл, /tmp/bbsnode1 , и если существование этого файла истинно, оно удаляет его. То, что я хотел бы сделать, это /tmp/bbsnode2 нескольких файлов ( /tmp/bbsnode2 , /tmp/bbsnode3 и /tmp/bbsnode4 ), удалить все из них. Но удалите их только в том случае, если они все существуют.

Вот что я до сих пор:

 if [ -f /tmp/bbsnode1 ] then /usr/bin/rm /tmp/bbsnode1 fi 

5 Solutions collect form web for “Как проверить, существует ли несколько файлов?”

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

 rm-all-or-none() { for f; do [ -f "$f" ] || { printf '%s is not an existing file, no files removed\n' "$f" >&2 return 1;} done rm -fv -- "$@" } 

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

 rm-all-or-none /tmp/bbsnode{1..4} 

Более длинная эквивалентная версия:

 rm-all-or-none() { for f in "$@"; do if [ -f "$f" ]; then : else printf '%s is not an existing file, no files removed\n' "$f" >&2 return 1 fi done rm -fv -- "$@" } 

Также см:

  • В Bash, когда к псевдониму, когда скрипту, а когда писать функцию?

Вы можете использовать произвольную команду, например ls для проверки файлов и удаления их в одной строке

 ls /tmp/bbsnode{1,2,3,4} &>/dev/null && rm /tmp/bbsnode{1,2,3,4} 

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

Краткое объяснение:

Возвращаемое значение ls не равно нулю, если один из файлов не существует. {1,2,3,4} является расширением скобки: он расширяется до строки для каждого номера: so /tmp/bbsnode{1,2,3,4} совпадает с /tmp/bbsnode1 /tmp/bbsnode2 /tmp/bbsnode3 /tmp/bbsnode4 . Команда && выполняет следующую команду только в том случае, если предыдущая команда имеет нулевое возвращаемое значение, и поэтому здесь rm выполняется только в том случае, если все 4 файла существуют. Наконец, &> /dev/null подавляет вывод ls ( &> перенаправленных как stdout и stderr , /dev/null избавляется от него).

Ниже другого решения с встроенными оболочками. Это похоже на то, что другие ответили, но без дополнительной функции или скрипта:

 set -- /tmp/bbsnode{1,2,3,4} (for f; do test -f "$f" || exit; done) && rm -- "$@" 

В этом конкретном случае вы можете сделать:

 set -- file[1-4] [[ $# -eq 4 ]] && rm -f -- "$@" 

Этот set file4 список аргументов именам файлов, которые соответствуют любым файлам file1 , file2 , file3 или file4 1, затем rm эти файлы, только если число аргументов равно 4, то есть, если все файлы существуют.


1: для простоты я использую file вместо /tmp/bbsnode

Самый простой способ – две команды: set -e и stat

 #!/bin/bash set -e # make script exit if there's errors main() { stat "$@" rm "$@" } main "$@" 

Как это работает

Ключ здесь set -e . Это немедленно выдает скрипт, если возникают ошибки. stat принимает список всех файлов, которые вы ему даете. Если файл отсутствует, он вернет статус выхода 1, что означает ошибку. Таким образом, ваш скрипт получит часть rm тогда и только тогда, когда не будет ошибок, связанных с stat

Побочные примечания

  • вы можете использовать stat "$@" > /dev/null для подавления вывода на экран
  • Использование функции main() не требуется, это просто стилистическое предпочтение автора.
  • как отметил rudimeier в комментариях, вы также можете использовать однострочный с этими двумя командами: stat "$@" && rm "$@" .

Тестовый забег:

 bash-4.3$ chmod +x remove_all_if_exist.sh bash-4.3$ touch /tmp/{file1,file2} bash-4.3$ ls /tmp/file* /tmp/file1 /tmp/file2 bash-4.3$ ./remove_all_if_exist.sh /tmp/file1 /tmp/file2 /tmp/file3 File: '/tmp/file1' Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: 801h/2049d Inode: 3423307 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1000/ xieerqi) Gid: ( 1000/ xieerqi) Access: 2016-11-04 17:44:06.587438784 -0600 Modify: 2016-11-04 17:44:06.587438784 -0600 Change: 2016-11-04 17:44:06.587438784 -0600 Birth: - File: '/tmp/file2' Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: 801h/2049d Inode: 3423308 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1000/ xieerqi) Gid: ( 1000/ xieerqi) Access: 2016-11-04 17:44:06.587438784 -0600 Modify: 2016-11-04 17:44:06.587438784 -0600 Change: 2016-11-04 17:44:06.587438784 -0600 Birth: - stat: cannot stat '/tmp/file3': No such file or directory bash-4.3$ ls /tmp/file* /tmp/file1 /tmp/file2 bash-4.3$ ./remove_all_if_exist.sh /tmp/file1 /tmp/file2 File: '/tmp/file1' Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: 801h/2049d Inode: 3423307 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1000/ xieerqi) Gid: ( 1000/ xieerqi) Access: 2016-11-04 17:44:06.587438784 -0600 Modify: 2016-11-04 17:44:06.587438784 -0600 Change: 2016-11-04 17:44:06.587438784 -0600 Birth: - File: '/tmp/file2' Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: 801h/2049d Inode: 3423308 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1000/ xieerqi) Gid: ( 1000/ xieerqi) Access: 2016-11-04 17:44:06.587438784 -0600 Modify: 2016-11-04 17:44:06.587438784 -0600 Change: 2016-11-04 17:44:06.587438784 -0600 Birth: - bash-4.3$ ls /tmp/file* ls: cannot access '/tmp/file*': No such file or directory bash-4.3$ 

Альтернатива с python:

 python -c 'import sys,os;f=sys.argv[1:];c=[os.path.exists(a) for a in f]; l = len(c)*[True]; result = [os.unlink(a) for a in f] if l == c else False; print result' /tmp/file1 /tmp/file2 
  • получить список аргументов командной строки с помощью sys.argv[1:]
  • построить список значений true-false, если существуют файлы
  • если все файлы возвращают True, отмените (удалите) их

Вы можете использовать этот скрипт с именем removing_group

 #!/usr/bin/bash function check { while (( "$#" )) ; do if [ -f "$1" ] ; then # echo "The file $1" ; shift ; else # echo "The's no file $1"; return 1 fi done return 0 } if check $@; then while (( "$#" )) ; do # echo "Remove $1" ; rm "$1" ; shift ; done fi 

Функция check проверяет все ее аргументы как обычные файлы. Если следующий файл не существует, функция возвращает 1 и ничего не происходит. Если все файлы существуют, то возвращается 0 будет обрабатываться, if check $@ , который будет удалять файлы по одному. Файлы для проверки и удаления, описанные как параметры в командной строке, например

 ./removing_group /tmp/bbsnode1 /tmp/bbsnode2 /tmp/bbsnode3 /tmp/bbsnode4 

или

 ./removing_group /tmp/bbsnode{1,2,3,4} 
  • переименуйте пакет файлов после чтения из исходного файла
  • Как передать аргументы скрипту, которые были сгенерированы другим скриптом
  • Как найти все квадратные изображения в каталоге
  • Условная grepping
  • Приближение числа с плавающей запятой с правильным округлением
  • Сбой сценария резервного копирования с параметрами команды rsync в цитируемой переменной
  • Создайте несколько имен пользователей и UID в Linux с помощью сценария оболочки
  • перебирать файлы и отправлять строки в качестве позиционных параметров в другой файл
  • Как использовать sed для замены строки, используя номер строки на удаленной машине, используя ssh?
  • Как найти точную строку без ведущего или конечного символа
  • Как найти следующий доступный суффикс файла (file_a.txt file_b.txt и т. Д.)
  • Linux и Unix - лучшая ОС в мире.