Я пишу сценарий ночной сборки на 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?
В дополнение к ответу Пола вы можете использовать $(dirname $PATH_TO_SOMEWHERE) и $(basename $PATH_TO_SOMEWHERE) для разделения на папку и каталог и сделать что-то вроде каталога и файла





Вы можете использовать команду "file", если вы действительно хотите узнать информацию о файле, а не полагаться на расширения.
Если вы чувствуете себя комфортно при использовании расширения, вы можете использовать команду grep, чтобы проверить, совпадает ли оно.
да, я знаю о команде file. Я действительно пробовал сопоставление на основе вывода указанной команды ... но я ужасно не справляюсь с этими if-операторами.
Думаю, вы хотите спросить: "Последние четыре символа $ file равны .txt?" Если да, вы можете использовать следующее:
if [ ${file: -4} == ".txt" ]
Обратите внимание, что пробел между file: и -4 является обязательным, поскольку модификатор «: -» означает нечто иное.
для этого вы также можете переименовать command.com в command.txt на компьютере с Windows.
Если вы хотите указать неравенство, не забудьте включить дополнительные скобки: if [[$ {file: -4}! = ".Txt"]]
@RamRajamony Почему необходимо использовать [[при проверке неравенства?
Я хотел указать на важность пробела после двоеточия. ${var:-4} не то же самое, что ${var: -4}; первый (без пробела) будет расширяться как '-4', если var не задан, второй (с пробелом) возвращает последние 4 символа var.
В bash это приведет к ошибке «[: ==: ожидается унарный оператор», если вы не заключите в кавычки первую переменную. Так что вместо этого if [ "${file: -4}" == ".txt" ].
В системе Unix вы просто не можете быть уверены, что файл .txt действительно является текстовым файлом. Лучше всего использовать «файл». Возможно, попробуйте использовать:
file -ib "$file"
Затем вы можете использовать список типов MIME для сопоставления или анализа первой части MIME, где вы получаете такие вещи, как «текст», «приложение» и т. д.
Поскольку file -i... включает кодировку mime, вы можете использовать file --mime-type -b ...
Делать
if [ "$file" == "*.txt" ]
как это:
if [[ $file == *.txt ]]
То есть двойные скобки и без кавычек.
Правая сторона == представляет собой узор ракушки.
Если вам нужно регулярное выражение, тогда используйте =~.
Я не знал об этом. Кажется, что это особый случай, когда правая часть == или! = Раскрывается как шаблон оболочки. Лично я думаю, что это яснее, чем мой ответ.
Я новичок в bash, и мне потребовалось некоторое время, чтобы понять, как использовать это в мультиусловном операторе if. Я делюсь им здесь на случай, если это кому-то поможет. if [[ ( $file == *.csv ) || ( $file == *.png ) ]]
@cheflo в целом подходит для нескольких условий. В этом конкретном случае вы также можете использовать if [[ $file =~ .*\.(csv|png) ]]. Он короче, понятнее, проще добавлять дополнительные расширения и его можно легко настроить (добавив "csv | png" в переменную).
Вы можете заключить файл в двойные кавычки. if [[ "$file" == *.txt ]] Если в имени файла есть пробелы, необходимо использовать двойные кавычки.
Стоит ли использовать этот ответ вместо принятого?
@shawnhcorey Нет необходимости указывать $ file в кавычках, даже если он содержит пробел. Команда [[не выполняет разделение слов (или расширение имени пути). Это одно из основных различий между [[и [, и одна из основных причин использования [[.
Я написал сценарий 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 показался бы более надежным и идиоматичным.
Это будет работать с самой простой оболочкой, более универсальной.
Думаю, что '$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 лучше зарезервировать на тот случай, когда тело цикла должно быть более сложным.
Подобно 'file', используйте более простой 'mimetype -b', который будет работать независимо от расширения файла.
if [ $(mimetype -b "$MyFile") == "text/plain" ]
then
echo "this is a text file"
fi
Обновлено: вам может потребоваться установить libfile-mimeinfo-perl в вашей системе, если mimetype недоступен
Вы должны прояснить, что сценарий mimetype доступен не во всех системах.
Готово, добавил libfile-mimeinfo-perl
Правильный ответ о том, как использовать расширение, доступное в имени файла в Linux:
${filename##*\.}
Пример печати всех расширений файлов в каталоге
for fname in $(find . -maxdepth 1 -type f) # only regular file in the current dir
do echo ${fname##*\.} #print extensions
done
В вашем ответе используется двойная обратная косая черта, но в вашем примере используется только одна обратная косая черта. Ваш пример правильный, ваш ответ - нет.
Это сломается, если у вас есть файл с пробелом в имени.