Как проверить расширение имени файла в сценарии bash?

Я пишу сценарий ночной сборки на bash.
Все отлично, за исключением одной маленькой загвоздки:


#!/bin/bash

for file in "$PATH_TO_SOMEWHERE"; do
      if [ -d $file ]
      then
              # do something directory-ish
      else
              if [ "$file" == "*.txt" ]       #  this is the snag
              then
                     # do something txt-ish
              fi
      fi
done;

Моя проблема заключается в том, чтобы определить расширение файла и затем действовать соответствующим образом. Я знаю, что проблема в операторе if, проверяющем текстовый файл.

Как определить, есть ли у файла суффикс .txt?

Это сломается, если у вас есть файл с пробелом в имени.

jfg956 03.08.2011 16:11

В дополнение к ответу Пола вы можете использовать $(dirname $PATH_TO_SOMEWHERE) и $(basename $PATH_TO_SOMEWHERE) для разделения на папку и каталог и сделать что-то вроде каталога и файла

McPeppr 17.05.2016 14:52
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
183
2
242 470
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Вы можете использовать команду "file", если вы действительно хотите узнать информацию о файле, а не полагаться на расширения.

Если вы чувствуете себя комфортно при использовании расширения, вы можете использовать команду grep, чтобы проверить, совпадает ли оно.

да, я знаю о команде file. Я действительно пробовал сопоставление на основе вывода указанной команды ... но я ужасно не справляюсь с этими if-операторами.

theman_on_vista 02.01.2009 18:57
Ответ принят как подходящий

Думаю, вы хотите спросить: "Последние четыре символа $ file равны .txt?" Если да, вы можете использовать следующее:

if [ ${file: -4} == ".txt" ]

Обратите внимание, что пробел между file: и -4 является обязательным, поскольку модификатор «: -» означает нечто иное.

для этого вы также можете переименовать command.com в command.txt на компьютере с Windows.

hometoast 09.06.2009 22:10

Если вы хотите указать неравенство, не забудьте включить дополнительные скобки: if [[$ {file: -4}! = ".Txt"]]

Ram Rajamony 21.07.2013 03:38

@RamRajamony Почему необходимо использовать [[при проверке неравенства?

PesaThe 09.12.2017 02:48

Я хотел указать на важность пробела после двоеточия. ${var:-4} не то же самое, что ${var: -4}; первый (без пробела) будет расширяться как '-4', если var не задан, второй (с пробелом) возвращает последние 4 символа var.

pbatey 19.07.2019 20:05

В bash это приведет к ошибке «[: ==: ожидается унарный оператор», если вы не заключите в кавычки первую переменную. Так что вместо этого if [ "${file: -4}" == ".txt" ].

Giles B 18.10.2019 18:03

В системе Unix вы просто не можете быть уверены, что файл .txt действительно является текстовым файлом. Лучше всего использовать «файл». Возможно, попробуйте использовать:

file -ib "$file"

Затем вы можете использовать список типов MIME для сопоставления или анализа первой части MIME, где вы получаете такие вещи, как «текст», «приложение» и т. д.

Поскольку file -i... включает кодировку mime, вы можете использовать file --mime-type -b ...

Wilf 15.06.2014 15:04

Делать

if [ "$file" == "*.txt" ]

как это:

if [[ $file == *.txt ]]

То есть двойные скобки и без кавычек.

Правая сторона == представляет собой узор ракушки. Если вам нужно регулярное выражение, тогда используйте =~.

Я не знал об этом. Кажется, что это особый случай, когда правая часть == или! = Раскрывается как шаблон оболочки. Лично я думаю, что это яснее, чем мой ответ.

Paul Stephenson 11.06.2009 12:12

Я новичок в bash, и мне потребовалось некоторое время, чтобы понять, как использовать это в мультиусловном операторе if. Я делюсь им здесь на случай, если это кому-то поможет. if [[ ( $file == *.csv ) || ( $file == *.png ) ]]

joelostblom 07.02.2015 04:09

@cheflo в целом подходит для нескольких условий. В этом конкретном случае вы также можете использовать if [[ $file =~ .*\.(csv|png) ]]. Он короче, понятнее, проще добавлять дополнительные расширения и его можно легко настроить (добавив "csv | png" в переменную).

jox 29.05.2016 13:10

Вы можете заключить файл в двойные кавычки. if [[ "$file" == *.txt ]] Если в имени файла есть пробелы, необходимо использовать двойные кавычки.

shawnhcorey 02.08.2016 14:02

Стоит ли использовать этот ответ вместо принятого?

Freedo 26.11.2018 05:02

@shawnhcorey Нет необходимости указывать $ file в кавычках, даже если он содержит пробел. Команда [[не выполняет разделение слов (или расширение имени пути). Это одно из основных различий между [[и [, и одна из основных причин использования [[.

Hontvári Levente 09.05.2020 09:19

Я написал сценарий bash, который проверяет тип файла, а затем копирует его в место, которое я использую для просмотра видео, которые я смотрел в Интернете, из моего кеша firefox:

#!/bin/bash
# flvcache script

CACHE=~/.mozilla/firefox/xxxxxxxx.default/Cache
OUTPUTDIR=~/Videos/flvs
MINFILESIZE=2M

for f in `find $CACHE -size +$MINFILESIZE`
do
    a=$(file $f | cut -f2 -d ' ')
    o=$(basename $f)
    if [ "$a" = "Macromedia" ]
        then
            cp "$f" "$OUTPUTDIR/$o"
    fi
done

nautilus  "$OUTPUTDIR"&

В нем используются идеи, аналогичные представленным здесь, надеюсь, это кому-то поможет.

Вы также можете:

   if [ "${FILE##*.}" = "txt" ]; then
       # operation for txt files here
   fi
case $FILE in *.txt ) ... ;; esac показался бы более надежным и идиоматичным.
tripleee 29.12.2012 17:15

Это будет работать с самой простой оболочкой, более универсальной.

Kemin Zhou 01.04.2021 06:50

Думаю, что '$PATH_TO_SOMEWHERE' - это что-то вроде '<directory>/*'.

В этом случае я бы изменил код на:

find <directory> -maxdepth 1 -type d -exec ... \;
find <directory> -maxdepth 1 -type f -name "*.txt" -exec ... \;

Если вы хотите сделать что-то более сложное с именами каталогов и текстовых файлов, вы можете:

find <directory> -maxdepth 1 -type d | while read dir; do echo $dir; ...; done
find <directory> -maxdepth 1 -type f -name "*.txt" | while read txtfile; do echo $txtfile; ...; done

Если в именах файлов есть пробелы, вы можете:

find <directory> -maxdepth 1 -type d | xargs ...
find <directory> -maxdepth 1 -type f -name "*.txt" | xargs ...

Это отличные примеры того, как вы делаете «циклы» в оболочке. Явные циклы for и while лучше зарезервировать на тот случай, когда тело цикла должно быть более сложным.

user49586 10.01.2014 01:30

Подобно 'file', используйте более простой 'mimetype -b', который будет работать независимо от расширения файла.

if [ $(mimetype -b "$MyFile") == "text/plain" ]
then
  echo "this is a text file"
fi

Обновлено: вам может потребоваться установить libfile-mimeinfo-perl в вашей системе, если mimetype недоступен

Вы должны прояснить, что сценарий mimetype доступен не во всех системах.

gilbertpilz 19.05.2017 03:48

Готово, добавил libfile-mimeinfo-perl

dargaud 20.05.2017 00:45

Правильный ответ о том, как использовать расширение, доступное в имени файла в Linux:

${filename##*\.} 

Пример печати всех расширений файлов в каталоге

for fname in $(find . -maxdepth 1 -type f) # only regular file in the current dir
    do  echo ${fname##*\.} #print extensions 
done

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

gilbertpilz 19.05.2017 03:52

Другие вопросы по теме