Команда для відображення довільного повідомлення, якщо певний файл існує


11

Чи існує команда для відображення повідомлення "Так", якщо певний файл існує? Якщо файл не існує, не потрібно надавати функціональність.

Відповіді:


25

Скористайтеся цим простим одношаровим Bash:

if [ -e FILENAME ] ; then echo Yes ; fi

Не В -eконтрольних правдивий , якщо FILENAMEіснує, то, незалежно від того , що він (файл, каталог, посилання, пристрій, ...).

Якщо ви хочете перевіряти лише звичайні файли, використовуйте -fнатомість, як сказав @Arronical .


18
[ -e FILENAME ] && echo Yes
Зеб МакКоркл

@ZebMcCorkle Правильно, це теж працює. Ви можете опублікувати це як окрему відповідь.
Командир байт

3
Якщо FILENAMEрозширення змінної або містить будь-які спеціальні символи, не забудьте процитувати його. наприклад , в скрипті [ -e "$1" ] && echo Yes.
Пітер Кордес

@PeterCordes якщо ви використовуєте Баш ви можете використовувати [[і ]]замість того, щоб цитувати змінну.
Холлоуей

1
@Holloway: так, але іноді потрібно писати портативні сценарії, для яких потрібен лише POSIX sh. Ось чому я дав безпечну версію цього замість того, щоб знижувати його та відхиляти баш-відповідь. Також зауважте, що цитувати розширення всередині не проблема [[ ]], завжди цитування - це хороша звичка для початківців, які не пам’ятають особливих правил для [[ ]]оператора або для арифметичних контекстів.
Пітер Кордес

10

Ви можете використовувати цей простий сценарій:

#!/bin/bash

if [[ -f $1 ]]; then
    echo "Yes"
    exit 0
else
    exit 1
fi

Збережіть як file-exists.sh. Потім у Терміналі наберіть chmod +x file-exists.sh.

Використовуйте його як: ./file-exists.sh FILEде ви замінюєте FILEфайл, який ви хочете перевірити, наприклад:

./file-exists.sh file.txt

Якщо file.txtіснує, Yesбуде надруковано на Термінал, і програма вийде зі статусом 0 (успіх). Якщо файл не існує, нічого не буде надруковано, і програма вийде зі статусом 1 (збій).

Якщо вам цікаво, чому я включив exitкоманду, читайте далі ...


Що з exitкомандою?

exitвикликає нормальне припинення процесу. Що це означає, це в основному: це зупиняє сценарій. Він приймає необов'язковий (числовий) параметр, який буде статусом виходу сценарію, який його викликав.

Цей статус виходу дає змогу вашим іншим сценаріям використовувати ваш file-existsсценарій, і це спосіб їх розуміння, існує файл чи ні.

Простий приклад, який використовує це для використання, - це сценарій (збережіть його як file-exists-cli.sh):

#!/bin/bash

echo "Enter a filename and I will tell you if it exists or not: "
read FILE
# Run `file-exists.sh` but discard any output because we don't need it in this example
./file-exists.sh $FILE &>> /dev/null
# #? is a special variable that holds the exit status of the previous command
if [[ $? == 0 ]]; then
    echo "$FILE exists"
else
    echo "$FILE does not exist"
fi

У звичайного , chmod +x file-exists-cli.shа потім запустити його: ./file-exists-cli.sh. Ви побачите щось подібне:

Файл існує ( exit 0):

➜  ~ ./file-exists-cli.sh 
Enter a filename and I will tell you if it exists or not: 
booleans.py
booleans.py exists

Файл не існує ( exit 1):

➜  ~ ./file-exists-cli.sh
Enter a filename and I will tell you if it exists or not: 
asdf
asdf does not exist

2
Добре, але ти повинен цитувати змінні посилання на кшталт "$1". Якщо в ній є простір, він зламається без лапок і можуть трапитися інші погані речі.
Джо

9

В оболонці bash в командному рядку.

if [[ -f /path/to/file ]]; then echo "Yes"; fi

Тут використовується умовний оператор bash -fі перевіряється, чи існує файл і чи є звичайним файлом. Якщо ви хочете перевірити наявність файлів, включаючи каталоги та посилання, тоді використовуйте -e.

Це чудовий ресурс для баш-умов.


1
Чому подвійні брекети?
командир байт

1
Я не фанат testу своєму оригінальному форматі, я знаю, що це надмірно, але це моя звичка.
Арронічний

7
@ByteCommander: подвійні брекети просто загалом кращі, ніж одинарні дужки. Вони є частиною синтаксису оболонки (замість того, щоб викликати [команду, яка, як правило, викликає вбудований модуль). Вони виправляють невідповідності та німі поведінки єдиної версії дужок. [Вбудований залишається сумісним, але я не бачу вагомих причин використовувати його в новому коді bash. (Якщо вам потрібно написати сценарії, сумісні з POSIX, які можуть працювати на старовинних оболонках чи щось інше.)
Нік Маттео

@kundor: Хоча, [як правило, погоджено, " як правило, це називається вбудованим" є сумнівним. type -a [для мене списки "shell buildin", потім " /usr/bin/[.
wchargin

1
@wchargin: Боюсь, я не розумію, на що ти потрапляєш. typeЗдається, ваші результати підтверджують те, що я сказав, ні?
Нік Маттео

5

Найкоротша команда робити те, що ви хочете, це:

test -e FILENAME && echo Yes

test -eперевірить, чи існує вказане ім’я у файловій системі. (Ви можете використовувати test -fобмеження лише до звичайних файлів. Докладніше див man test.)

Якщо задана умова оцінюється як істинне, тоді testповертається успішний статус виходу (інакше він повертає статус відмови). Ми поєднуємо дві команди, використовуючи &&, що означає "виконати наступну команду, якщо попередня команда вийшла зі статусом успіху". Наступна команда просто друкує Yesна стандартному виході; у випадку інтерактивної оболонки - на терміналі.

Це дозволяє уникнути додаткових текстових матеріалів ifзаяви, але дає такий же результат. Використання &&(або його протилежне ||) для зв'язання команд разом працює добре, якщо бере участь лише одна команда. Якщо ви хочете зробити більше, ніж виконати одну команду у відповідь на статус виходу однієї команди, то використання ifсинтаксису швидко стає набагато читабельніше.

Як вже вказувалося в інших відповідях, еквівалентною ifконструкцією стилю було б:

if test -e FILENAME; then echo Yes; fi

або альтернативно:

if test -e FILENAME
then
    echo Yes
fi

Для цих цілей, [і testеквівалентні, за винятком того, що [вимагає закінчується ].


4

Для вирішення цього типу питань існує кілька способів, і ось ще один: використовувати findкоманду з -execпрапором. Шлях до файлу можна розділити на дві частини, find /etcяка встановлює каталог та -name FILENAMEвизначає назву файлу (duh!). -maxdepthбуде findпрацювати /etcлише з каталогом і не сходитиме до підкаталогів

adminx@L455D:~$ find /etc -maxdepth 1  -name passwd -exec printf "YES\n" \;
YES
adminx@L455D:~$ find /etc -maxdepth 1  -name passwd1 -exec printf "YES\n" \;
adminx@L455D:~$ 

Інший спосіб через stat:

adminx@L455D:~$ stat /etc/passwd1 &>/dev/null && echo YES
adminx@L455D:~$ stat /etc/passwd &>/dev/null && echo YES
YES

І альтернативно через python:

>>> import os
>>> if os.stat('/etc/passwd'): 
...    print 'YES'
... 
YES
>>> if os.stat('/etc/passwd1'): 
...    print 'YES'
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 2] No such file or directory: '/etc/passwd1'

Або альтернатива короткого командного рядка:

 python -c "from os.path import exists; print 'Yes' if exists('/etc/fstab') else '' "
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.