Питання Як визначити, чи не існує звичайний файл у Bash?


Я використовував наступний скрипт, щоб побачити, чи існує файл:

#!/bin/bash

FILE=$1     
if [ -f $FILE ]; then
   echo "File $FILE exists."
else
   echo "File $FILE does not exist."
fi

Який правильний синтаксис для використання, якщо я хочу перевірити лише файл ні існувати?

#!/bin/bash

FILE=$1     
if [ $FILE does not exist ]; then
   echo "File $FILE does not exist."
fi

2517
2018-03-12 14:48


походження


Я знайшов це список bash умовних висловлювань дуже корисний. - Saulius Žemaitaitis
Будучи лінивою людиною, якою я, як правило, використовувала таку дурну конструкцію: if [ -f $FILE ]; then; else; echo "File $FILE does not exist."; fi; Напевно, добре, що я знайшов це питання і навчився робити це належним чином. :) - Alderath
Для того, щоб бути поважним, слід сказати "звичайний файл", оскільки більшість документів UNIX / POSIX загальним чином позначають всі типи записів файлової системи просто "файли", наприклад, символічне посилання є типом файлу, як і названа трубка , звичайний файл, каталог, блок спеціальний, особливий символ, сокет і т. д. - kevinarpe
@ kevinarpe, якщо ви хочете перевірити, чи щось існує, використовувати -e. -f не збирати каталоги, символьні посилання та ін - Benubird
Щоб бути в безпеці, завжди використовуйте подвійні лапки, щоб правильно обробляти імена файлів з пробілами, наприклад, FILE=$1 -> FILE="$1" і if [ -f $FILE ]; -> if [ -f "$FILE" ]; - kevinarpe


Відповіді:


The тест команда ([ тут) має "не" логічний оператор, який є знаком оклику (подібним багатьом іншим мовам). Спробуйте це:

if [ ! -f /tmp/foo.txt ]; then
    echo "File not found!"
fi

3528
2018-03-12 14:50



Я трохи намагався знайти правильний синтаксис для "якщо не існує жодного з двох файлів". Нижче обидва роботи: if [ ! \( -f "f1" -a -f "f2" \) ] ; then echo MISSING; fi  if [ ! -f "f1" ] || [ ! -f "f2" ] ; then echo MISSING; fi - mivk
@DavidWinterbottom Ще більш соковита: [ -f /tmp/foo.txt ] || echo "File not found!" - David W.
Параметр може бути будь-яким з наступних: -e: Returns true value, if file exists  -f: Return true value, if file exists and regular file  -r: Return true value, if file exists and is readable  -w: Return true value, if file exists and is writable  -x: Return true value, if file exists and is executable  -d: Return true value, if exists and is a directory - SD.
Якщо ви хочете використати 2 умови в операції if, використовуйте оператор -a, це означає, що є AND. Я думаю, це також можливо з &, якщо ви використовуєте оператор [[]] - GroundZero
Існує асиметрія в використанні ! -f з && проти використання -f з ||. Це пов'язано з кодом виходу, який повертається перевіркою не існування / існування. Якщо вам потрібна ваша лінія, щоб завжди виходити з коду з виходом 0 (і іноді ви не бажаєте цього обмеження), ці два підходи не є взаємозамінними. Крім того, просто використовуйте if твердження, і вам більше не доведеться турбуватися про код виходу вашої перевірки не існування / існування. - A-B-B


Тестування файлів Bash

-b filename - Блокувати спеціальний файл
-c filename - Спеціальний файл символів
-d directoryname - Перевірте існування каталогу
-e filename - Перевірте існування файлу незалежно від типу (вузол, каталог, сокет тощо).
-f filename - Перевірте, чи існує звичайний файл, а не каталог
-G filename - Перевірте, чи існує файл і який належить ефективному ідентифікатору групи
-G filename set-group-id - Істина, якщо файл існує, і є set-group-id
-k filename - Клейкий біт
-L filename - Символічна посилання
-O filename - Істина, якщо файл існує та належить ефективному ідентифікатору користувача
-r filename - Перевірте, чи файл є читабельним
-S filename - Перевірте, чи файл є сокетом
-s filename - Перевірте, чи файл відрізняється від нуля
-u filename - Перевірте, чи встановлений файл set-user-id bit
-w filename - Перевірте, чи файл можна записати
-x filename - Перевірте, чи файл виконуваний

Як використовувати:

#!/bin/bash
file=./file
if [ -e "$file" ]; then
    echo "File exists"
else 
    echo "File does not exist"
fi 

А. тестовий вираз може бути відхилено, використовуючи ! оператор

#!/bin/bash
file=./file
if [ ! -e "$file" ]; then
    echo "File does not exist"
else 
    echo "File exists"
fi 

428
2018-01-16 14:25



@ 0x90 Якщо ви хочете, ви можете редагувати свій пост і додати його до списку. Я думаю, ви маєте на увазі: -n String - Перевірте, чи довжина рядка не дорівнює нулю. Або ви маєте на увазі file1 -nt file2 - Перевірте, чи файл1 новий, то файл 2 (ви також можете використовувати -ot для старших) - GroundZero
Про -n: The unary operator -z tests for a null string, while -n or no operator at all returns True if a string is not empty. ~ ibm.com/developerworks/library/l-bash-test/index.html - GroundZero


Ви можете скасувати вираз з "!":

#!/bin/bash
FILE=$1

if [ ! -f "$FILE" ]
then
    echo "File $FILE does not exist"
fi

Відповідна сторінка людини є man test або, еквівалентно man [ - або help test або help [ для вбудованої команди bash.


250
2018-03-12 14:50



В баш, [ є вбудованим. Тому відповідна інформація є достатньою мірою отриманою help [... але це показує це [ є синонімом для test внаслідок чого відповідна інформація є достатньою help test. Див. Також Bash Conditional Expression розділ в посібнику. - gniourf_gniourf
@gniourf_gniourf: Так, але вбудований баш [ команда веде себе дуже подібно до зовнішнього [ команда, так теж man test або man [ дасть вам гарне уявлення про те, як це працює. - Keith Thompson
@ Кейт Томпсон за винятком того, що баш побудований [ має більше перемикачів, ніж зовнішня команда [ знайдений у моїй системі ... Загалом я вважаю, що краще прочитати документацію, що стосується даного інструмента, а не документації, специфічної для іншого невизначено пов'язаного. Хоча я можу помилятися ;) - gniourf_gniourf


[[ -f $FILE ]] || printf '%s does not exist!\n' "$FILE"

Також можливо, що файл - це зламане символічне посилання або нестандартний файл, як-от, наприклад, сокет, пристрій або FIFO. Наприклад, щоб додати чек для порушених символьних посилань:

if [[ ! -f $FILE ]]; then
    if [[ -L $FILE ]]; then
        printf '%s is a broken symlink!\n' "$FILE"
    else
        printf '%s does not exist!\n' "$FILE"
    fi
fi

110
2018-03-12 14:52



Чи можу я запитати, чому два "[" в тесті? (наприклад [[! -a $ FILE]]). Я спробував всі варіанти, згадані в коробці соляріс, і тільки той, хто працював, так вдячний, але чому? - Dimitrios Mistriotis
Подвійні дужки є "сучасним" розширенням; наприклад, вони не будуть розщеплювати слова (наприклад, для імен файлів з пробілами) і все ще працюють для порожніх рядків: mywiki.wooledge.org/BashFAQ/031 - bw1024
відповідно до tldp.org/LDP/abs/html/fto.html -а є ідентичним по-е. Він був "застарілим", і його використання не рекомендується. Так чи інакше +1 для згадування, щоб перевірити на розбиті символьні посилання - Luca Borrione
@dimitrismistriotis два "[" - це не портативне розширення, яке реалізовано (інакше) за допомогою zsh & bash; як правило, слід уникати цього, якщо це взагалі можливо. - Good Person
Я проголосував за це тому, що він використовував [[. Це широко використовується розширення. Якщо ви знаєте, що використовуєте bash, то немає причин не використовувати його. Це набагато менше помилок, ніж [. - Michael Potter


Варто зазначити, що якщо вам потрібно виконати одну команду, ви можете скоротити її

if [ ! -f "$file" ]; then
    echo "$file"
fi

до

test -f "$file" || echo "$file"

або

[ -f "$file" ] || echo "$file"

80
2017-08-11 09:15



Дякую! Потрібна альтернатива, яка не використовує [[]] - Jonathan


Я вважаю за краще зробити наступний лайнер, в POSIX формат оболонки:

$ [ -f "/$DIR/$FILE" ] || echo "$FILE NOT FOUND"

$ [ -f "/$DIR/$FILE" ] && echo "$FILE FOUND"

Для пари команд, як я б робив у сценарії:

$  [ -f "/$DIR/$FILE" ] || { echo "$FILE NOT FOUND" ; exit 1 ;}

Як тільки я почав це робити, я рідко використовую повністю набраний синтаксис!


57
2017-10-18 16:09



Перш за все, посилання, які не котируються, є помилковими. Що сказав, де він говорить будь-який bash manpage, що [ або test вбудований тест для існування файлу аргументу за замовчуванням (на відміну від -e)? Чи не буде це неоднозначним? AFAIK (і AIUI розділ "Умовні вирази") єдине, що тестується під вашим підходом, полягає в тому, що аргумент не є порожнім (або невизначеним), тобто в даному випадку є тавтологією (нехай $DIR = '' і $FILE = '', то аргумент все одно '//') - PointedEars
Доказ: ls /foo, результат ls: cannot access /foo: No such file or directory. [ /foo ] && echo 42, результат 42. GNU bash, версія 4.2.37 (1) -редак (i486-pc-linux-gnu). - PointedEars
@PointedEars: я не зміг вказати -f варіант, в той момент я написав цю відповідь. Очевидно, що ви завжди можете використовувати -e, якщо ви не впевнені, що це буде звичайний файл. Крім того, у всіх моїх скриптах я цитую ці конструкції, я, мабуть, просто представив це без адекватної перевірки. - TechZilla
ACK Але ви, напевно, знаєте, що один вкладиш не може вирішити проблему ще раз: [ $condition ] && if_true || if_false є схильною до помилок. У будь-якому випадку я знаходжу [ ! -f "$file" ] && if_not_exists легше читати і розуміти, ніж [ -f "$file" ] || if_not_exists. - PointedEars


Щоб перевірити існування файлу, параметр може бути будь-яким з наступних:

-e: Returns true if file exists (regular file, directory, or symlink)
-f: Returns true if file exists and is a regular file
-d: Returns true if file exists and is a directory
-h: Returns true if file exists and is a symlink

Усі наступні тести застосовуються до звичайних файлів, каталогів і символів:

-r: Returns true if file exists and is readable
-w: Returns true if file exists and is writable
-x: Returns true if file exists and is executable
-s: Returns true if file exists and has a size > 0

Приклад сценарію:

#!/bin/bash
FILE=$1

if [ -f "$FILE" ]; then
   echo "File $FILE exists"
else
   echo "File $FILE does not exist"
fi

36
2017-12-19 12:47





Ви повинні бути обережними щодо бігу test для нечіткої змінної, оскільки це може призвести до несподіваних результатів:

$ [ -f ]
$ echo $?
0
$ [ -f "" ]
$ echo $?
1

Рекомендація зазвичай полягає в тому, щоб тестована змінна була оточена подвійними лапками:

#!/bin/sh
FILE=$1

if [ ! -f "$FILE" ]
then
   echo "File $FILE does not exist."
fi

28
2018-01-24 19:43



Рекомендація має бути кожен змінна оточена подвійними лапками, якщо ви точно не знаєте, що у вас є один з рідкісних випадків, коли це непотрібно, або один з ще рідких випадків, коли це шкідливо. (І ні, це не одне з них.) - Uwe
Ви хотіли б розібратися, чому це не так, як використовувати подвійну лапку? В іншому випадку я не бачу коректності в коментарях. - artdanil
Я мав на увазі: це не один з рідкісних випадків, коли це непотрібно або шкідливо. Програміст оболонки повинен звикнути до (майже) кожної змінної в подвійних лапках; це правило не обмежується [ ... ]. - Uwe
Дивись також stackoverflow.com/questions/10067266/... - tripleee


Є три різні способи зробити це:

  1. Відхилити статус виходу з bash (жодна інша відповідь не сказала цього):

    if ! [ -e "$file" ]; then
        echo "file does not exist"
    fi
    

    Або:

    ! [ -e "$file" ] && echo "file does not exist"
    
  2. Відхилити тест всередині тестової команди [ (так виглядає більшість відповідей, які раніше подавали):

    if [ ! -e "$file" ]; then
        echo "file does not exist"
    fi
    

    Або:

    [ ! -e "$file" ] && echo "file does not exist"
    
  3. Закон про те, що результат тесту є негативним (|| замість &&):

    Тільки:

    [ -e "$file" ] || echo "file does not exist"
    

    Це виглядає нерозумно (IMO), не використовуйте його, якщо ваш код не повинен бути портативним до оболонки Bourne (наприклад, /bin/sh Solaris 10 або раніше), у яких бракує оператора заперечення трубопроводу (!):

    if [ -e "$file" ]; then
        :
    else
        echo "file does not exist"
    fi
    

18
2017-08-05 18:10



Будь-яка переносимість різниця між ! [ і [ !? - Frozen Flame
The ! [  це POSIX для оболонок трубопроводів 2.9.2 (будь-яка команда)  Otherwise, the exit status shall be the logical NOT of the exit status of the last command і [ !   це POSIX для тестування  ! expression True if expression is false. False if expression is true. Таким чином, обидва POSIX, і з мого досвіду, обидва підтримуються широко.
@FrozenFlame, оболонка Борна не мала ! ключове слово, яке було введено оболонкою Корна. Окрім можливого для Solaris 10 та старших, навряд чи ви натрапите на оболонку Борна в ці дні. - Stephane Chazelas


Ви можете зробити це:

[[ ! -f "$FILE" ]] && echo "File doesn't exist"

або

if [[ ! -f "$FILE" ]]; then
    echo "File doesn't exist"
fi

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


14
2018-04-28 19:40



Це не баш-специфічний. Синтаксис походить від оболонки Korn, а також доступний у zsh і bash. Він має обмежені переваги над стандартом [ корисні тут, хоча. - Stephane Chazelas
регулярний файли (як перевірено -f) та каталоги це всього два з багатьох різних типів файли. Є також розетки, символічні посилання, пристрої, FIFO, двері ... [ -e перевірятиме існування файлу (будь-якого типу, включаючи звичайний, fifo, каталог ...) після дозволу символічного посилання. - Stephane Chazelas
@StephaneChazelas: Я не бачу жодної теги ksh або zsh. Ми говоримо про bash або щось, що стандартизовано на більшості Unix-систем. Отже, в контексті, це конкретна баш. ОП не потрібно знати про кожен, чого там немає: D - Jahid
Це був коментар до "Баш специфічний" частина вашої відповіді. - Stephane Chazelas
@StephaneChazelas: Так, і в межах контексту (bash і стандарт sh), це bash конкретний. Я не бачу точки у вашому другому коменті, це абсолютно поза контекстом. ОП не потрібно -e, він потребує -f. - Jahid