#!/bin/sh
TMP=$(cd Folder && ls)
for name in $TMP; do
if [[ "${name}" != *"a"* -a ${name} == *"b"* ]] ;then
echo $name
fi
done
我试着输出没有“a”而是“b”的名字。这就是我所犯的错误:
./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
我在这里做错什么了?
发布于 2020-12-21 19:19:38
您的主要问题是在由[[ ... ]]
执行的脚本中使用/bin/sh
中的模式匹配,该脚本不支持这些类型的测试。另见题为当从sh文件运行时,Shell脚本将抛出一个未找到的错误.但是,如果手动输入,这些命令可以工作。的问题
另一个问题是,在将ls
的输出拆分为空格、制表符和换行符上的单词并将文件名全局化到生成的单词之前,您要将它组合成一个字符串。然后,循环处理这个结果。
相反:
#!/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中,您可以对[[ ... ]]
模式匹配测试进行相同的操作,就像您试图自己做的那样:
#!/bin/bash
cd Folder || exit 1
shopt -s nullglob
for name in *b*; do
[[ $name != *a* ]] && printf '%s\n' "$name"
done
另请参阅:
发布于 2020-12-21 19:35:09
若要在Folder
中打印包含b
而非a
的文件名,请在zsh
及其~
(除/和-不) glob操作符中打印:
#! /bin/zsh -
set -o extendedglob
print -rC1 -- Folder/(*b*~*a*)(N:t)
(删除N
(对于nullglob
,如果您希望在没有匹配文件的地方报告错误)。
在ksh93
(引入该[[...]]
运算符(它不是标准sh
语法的一部分)及其&
(和)和!(...)
( not )操作符的shell中:
#! /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运算符的效果,并使用|
(或)实现和:
#! /bin/bash -
(
shopt -s extglob nullglob
cd ./Folder &&
set -- !(!(*b*)|*a*) &&
(($# > 0)) &&
printf '%s\n' "$@"
)
在标准sh
语法中:
#! /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
中进行模式匹配。您甚至可以使用帮助函数:
contains()
case "$1" in
(*"$2"*) true;;
(*) false;;
esac
把…当作:
if contains foobar o; then
echo foobar contains o
fi
if ! contains foobar z; then
echo foobar does not contain o
fi
if
contains "$file" b &&
! contains "$file" a
then
printf '%s\n' "$file contains b and not a "
fi
https://unix.stackexchange.com/questions/625568
复制相似问题