首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Shell :检查字符串是否包含指定的字符。

Shell :检查字符串是否包含指定的字符。
EN

Unix & Linux用户
提问于 2020-12-21 19:13:37
回答 2查看 2.1K关注 0票数 -1
代码语言:javascript
运行
复制
#!/bin/sh

TMP=$(cd Folder && ls)

for name in $TMP; do

  if [[ "${name}" != *"a"* -a ${name} == *"b"* ]] ;then
   echo $name
  fi

done

我试着输出没有“a”而是“b”的名字。这就是我所犯的错误:

代码语言:javascript
运行
复制
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found

我在这里做错什么了?

EN

回答 2

Unix & Linux用户

回答已采纳

发布于 2020-12-21 19:19:38

您的主要问题是在由[[ ... ]]执行的脚本中使用/bin/sh中的模式匹配,该脚本不支持这些类型的测试。另见题为当从sh文件运行时,Shell脚本将抛出一个未找到的错误.但是,如果手动输入,这些命令可以工作。的问题

另一个问题是,在将ls的输出拆分为空格、制表符和换行符上的单词并将文件名全局化到生成的单词之前,您要将它组合成一个字符串。然后,循环处理这个结果。

相反:

代码语言:javascript
运行
复制
#!/bin/sh

cd Folder || exit 1

for name in *b*; do
    [ -e "$name" ] || [ -L "$name" ] || continue
    case $name in (*a*) ;; (*) printf '%s\n' "$name"; esac
done

这个循环遍历Folder目录中所有包含字母b的文件,然后打印其中不包含a的文件。a字符的测试是使用case ... esac完成的。*a*模式匹配文件名中的a字符(如果有),在这种情况下什么都不会发生。printf语句在“默认情况”中,如果字符串中没有a,则执行该语句。

使用-e-L的测试是为了确保我们捕捉到循环模式不匹配的边缘情况。在这种情况下,模式将保持未展开,因此为了确保我们能够区分未展开的模式和实际存在的文件,我们使用-e进行测试。-L测试的目的是捕捉符号链接的进一步边缘情况,该符号链接具有与循环模式相同的名称,但不指向任何有效的位置。下面的bash代码不需要这样做,因为它使用了nullglob shell选项(在/bin/sh中不可用)。

*b*模式的扩展上运行循环而不是任何ls输出都有好处,这也可以处理包含空格、制表符、换行符和文件名全局字符的文件名(文件名永远不会放在一个字符串中,然后我们尝试迭代)。

bash shell中,您可以对[[ ... ]]模式匹配测试进行相同的操作,就像您试图自己做的那样:

代码语言:javascript
运行
复制
#!/bin/bash

cd Folder || exit 1

shopt -s nullglob

for name in *b*; do
    [[ $name != *a* ]] && printf '%s\n' "$name"
done

另请参阅:

票数 5
EN

Unix & Linux用户

发布于 2020-12-21 19:35:09

若要在Folder中打印包含b而非a的文件名,请在zsh及其~ (除/和-不) glob操作符中打印:

代码语言:javascript
运行
复制
#! /bin/zsh -
set -o extendedglob
print -rC1 -- Folder/(*b*~*a*)(N:t)

(删除N (对于nullglob,如果您希望在没有匹配文件的地方报告错误)。

ksh93 (引入该[[...]]运算符(它不是标准sh语法的一部分)及其& (和)和!(...) ( not )操作符的shell中:

代码语言:javascript
运行
复制
#! /bin/ksh93 -
(
  CDPATH= cd Folder &&
    set -- ~(N)@(*b*&!(*a*)) &&
    (($# > 0)) &&
    printf '%s\n' "$@"
)

使用bash shell (与zsh类似,也复制了ksh的[[...]]运算符),使用extglob支持ksh88 glob运算符,使用nullglob获得zsh的N glob限定符或ksh93's ~(N) glob运算符的效果,并使用| (或)实现和:

代码语言:javascript
运行
复制
#! /bin/bash -
(
  shopt -s extglob nullglob
  cd ./Folder &&
    set -- !(!(*b*)|*a*) &&
    (($# > 0)) &&
    printf '%s\n' "$@"
)

在标准sh语法中:

代码语言:javascript
运行
复制
#! /bin/sh -
(
  CDPATH= cd Folder || exit
  set -- [*]b[*] *b*
  [ "$1/$2" = '[*]b[*]/*b*' ] && exit # detect the case where the pattern
                                      # expands to itself because there's
                                      # no match as there's no nullglob
                                      # equivalent in sh
  shift
  for i do
    case $i in
      (*a*) ;;
      (*) set -- "$@" "$i"
    esac
    shift
  done
  [ "$#" -gt 0 ] && printf '%s\n' "$@"
)

请注意,如果您已经读取了对cd的访问权限,但是没有搜索访问权限,那么使用Folder的解决方案将无法工作。

更广泛地说,要回答如何在sh中检查字符串是否包含另一个字符串的一般问题,最好使用case构造,这就是如何在sh中进行模式匹配。您甚至可以使用帮助函数:

代码语言:javascript
运行
复制
contains()
  case "$1" in
    (*"$2"*) true;;
    (*) false;;
  esac

把…当作:

代码语言:javascript
运行
复制
if contains foobar o; then
  echo foobar contains o
fi
代码语言:javascript
运行
复制
if ! contains foobar z; then
  echo foobar does not contain o
fi
代码语言:javascript
运行
复制
if
  contains "$file" b &&
    ! contains "$file" a
then
  printf '%s\n' "$file contains b and not a "
fi
票数 6
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/625568

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档