我正在尝试创建一个非常基本的 bash 脚本,告诉用户在继续之前是否输入了正确的脚本文件格式。例如:
echo "Input .txt file here:"
read file
if $file = *.txt
then
echo "File is in correct format."
else
echo "File is not in correct format. Please recheck your file."
fi
可以用什么来做到这一点?
命令(如下)不起作用,只是报告“其他”,而不是做我真正想做的事情。
$file = *.txt
答案1
当然,仅仅文件扩展名并不是文件格式。这只是任何人都可以通过简单的操作来更改的文本:
mv image.png word.txt
话虽这么说,在这种情况下,您可以简单地使用以下basename
命令:
base=`basename "$file" .txt`
if test "$base" != "$file"
then
echo "Success!"
else
echo "Wrong extension..."
fi
答案2
您可以尝试以下脚本:
if [ ".$(echo "$file"| cut -d. -f2)" == ".txt" ]
then
echo "File is in correct format."
else
echo "File is not in correct format. Please recheck your file."
fi
.
如果您的文件名有多个(点),您可以使用以下命令
if [ ".$(echo "$file"| awk -F. '{print $NF}')" == ".txt" ]
答案3
好吧,让我们回顾一下您要做什么。首先要意识到的是,你不想检查文件名是否为“ *.txt
”,你想看看它是否是与模式匹配” *.txt
“。此外,您还会在 Unix 脚本编写中遇到多种不同类型的模式;最常见的是通配符(或“glob”)模式和正则表达式(正则表达式语法有许多版本)。这里有一个全局模式。
因此,您需要一个进行全局模式匹配的工具。 (好吧,您也可以用不同的语法重写模式,或者采用完全不同的方法来检查扩展;但我们暂时坚持使用 glob 模式匹配。)
其次,您在声明中使用它if
。语句中的条件(和if
之间的东西)是if
then
命令(或者至少是类似命令的东西)。该if
语句取决于该命令是成功还是失败。if
语句中最常用的命令之一是[
,它是一个命令,如下所示:
if [ "$file" = "*.txt" ]; then
看起来[
像是某种 shell 语法或奇怪的括号,但事实并非如此,它只是一个常规命令(大部分相当于该test
命令)。但它是一个常规命令,要求其最后一个参数为“ ]
”(同样,不是真正的右括号,只是常规命令参数),并将其其余参数解析为逻辑表达式。请man [
参阅 其语法。另外,请注意,我对"$file"
和都加了双引号,"*.txt"
因为(作为普通命令参数)文件名将受到分词的影响,并且它们都将受到通配符扩展的影响,这可能会对表达式语法造成严重破坏。
但[
不进行模式匹配。它可以进行字符串和数字(整数)比较,但不能进行模式匹配。所以我们需要寻找其他地方。
如果您使用 bash(或 zsh 甚至 ksh,但是不是dash 或其他一些更基本的 shell),您可以使用[[ ]]
.不同于[
此是shell 语法而不是常规命令,它本质上是[
.还有它能=
与运算符进行模式匹配如果您将右侧不加引号。也就是说,这将进行文字字符串比较:
if [[ "$file" = "*.txt" ]]; then
这将进行全局模式修补:
if [[ "$file" = *.txt ]]; then
(请注意,实际上您不需要$file
对其中任何一个进行双引号,但我更喜欢自动对变量引用进行双引号,因为双引号它们几乎总是安全的,而将它们不加引号通常是不安全的,并且与需要引用的异常相比,更容易记住需要不引用的异常。)
所以,最后一个命令是你可能的答案假如您正在使用支持的 shell [[ ]]
(即,如果您使用的是 bash shebang#!/bin/bash
或#!/usr/bin/env bash
,而不是通用的 sh )。
如果您使用 plain sh
,那么我们必须稍微更改一下规则。在通用 POSIX shell 中进行通配符模式匹配的最简单方法是case
使用if
.这很好,因为通配符模式匹配就是case
生来要做的:
case "$file" in
*.txt )
echo "File is in correct format." ;;
* )
"File is not in correct format. Please recheck your file." ;;
esac
请注意,模式*
(匹配与早期模式不匹配的任何内容)的功能类似于语句else
中的子句if
。此外,语法需要一些时间来适应,在)
每个模式和匹配的命令之间以及;;
在每个模式命令的末尾。
如果我们从“我想匹配 glob 模式”切换到“我想查看文件名是否以 '.txt' 结尾”,还有其他选项。有几种(POSIX 标准)方法可以通过在文件名变量扩展上使用修饰符来实现此目的。例如,将从变量值的末尾${var%pattern}
删除匹配项(pattern
如果它匹配)。因此,一个标准技巧是尝试从文件名末尾删除“.txt”,然后查看它是否发生变化。如果是,则“.txt”匹配;如果没有,那就没有。像这样:
if [ "$file" != "${file%.txt}" ]; then
请注意,这使用了不等于测试 ( !=
),因为只有成功从末尾删除“.txt”,字符串才会不同。
您也可以删除最后一个“.”。在文件名中${file##*.}
(看看剩下的是否是“txt”),但这有一个问题,它会认为文件名“txt”匹配。哎呀。