所以我正在制作一个高级删除脚本。想法是用户为需要删除的内容输入grep regex,脚本对所有内容执行rm操作。基本上不需要每次都直接在命令行中编写所有代码。
到目前为止,这是我的脚本:
#!/bin/bash
# Script to delete files passed to it
if [ $# -ne 1 ]; then
echo "Error! Script needs to be run with a single argument that is the regex for the files to delete"
exit 1
fi
IFS=$'\n'
files=$(ls -a | grep $1 | awk '{print "\"" $0 "\"" }')
## TODO ensure directory support
echo "This script will delete the following files:"
for f in $files; do
echo " $f"
done
valid=false
while ! $valid ; do
read -p "Do you want to proceed? (y/n): "
case $REPLY in
y)
valid=true
echo "Deleting, please wait"
echo $files
rm ${files}
;;
n)
valid=true
;;
*)
echo "Invalid input, please try again"
;;
esac
done
exit 0
我的问题是当我实际执行“rm”操作时。我不断收到错误,说没有这样的文件或目录。
这是我正在使用的目录:
drwxr-xr-x 6 user staff 204 May 9 11:39 .
drwx------+ 51 user staff 1734 May 9 09:38 ..
-rw-r--r-- 1 user staff 10 May 9 11:39 temp two.txt
-rw-r--r-- 1 user staff 6 May 9 11:38 temp1.txt
-rw-r--r-- 1 user staff 6 May 9 11:38 temp2.txt
-rw-r--r-- 1 user staff 10 May 9 11:38 temp3.txt
我正在调用这样的脚本:easydelete.sh'^ tem'
这是输出:
This script will delete the following files:
"temp two.txt"
"temp1.txt"
"temp2.txt"
"temp3.txt"
Do you want to proceed? (y/n): y
Deleting, please wait
"temp two.txt" "temp1.txt" "temp2.txt" "temp3.txt"
rm: "temp two.txt": No such file or directory
rm: "temp1.txt": No such file or directory
rm: "temp2.txt": No such file or directory
rm: "temp3.txt": No such file or directory
如果我尝试直接删除其中一个文件,它可以正常工作。如果我甚至在调用“rm”之前传递了打印出的整个字符串,它就可以正常工作。但是当我使用数组时,它会失败。
我知道我正在处理数组错误,只是不确定我做错了什么。任何帮助,将不胜感激。感谢。
答案 0 :(得分:3)
改为考虑:
# put all filenames containing $1 as literal text in an array
#files=( *"$1"* )
# ...or, use a grep with GNU extensions to filter contents into an array:
# this passes filenames around with NUL delimiters for safety
#files=( )
#while IFS= read -r -d '' f; do
# files+=( "$f" )
#done < <(printf '%s\0' * | egrep --null --null-data -e "$1")
# ...or, evaluate all files against $1, as regex, and add them to the array if they match:
files=( )
for f in *; do
[[ $f =~ $1 ]] && files+=( "$f" )
done
# check that the first entry in that array actually exists
[[ -e $files || -L $files ]] || {
echo "No files containing $1 found; exiting" >&2
exit 1
}
# warn the user
echo "This script will delete the following files:" >&2
printf ' %q\n' "${files[@]}" >&2
# prompt the user
valid=0
while (( ! valid )); do
read -p "Do you want to proceed? (y/n): "
case $REPLY in
y) valid=1; echo "Deleting; please wait" >&2; rm -f "${files[@]}" ;;
n) valid=1 ;;
esac
done
我将在下面详细介绍:
files
必须明确地创建为一个实际是数组的数组 - 否则,它只是一个包含大量文件的字符串。
这是一个数组:
files=( "first file" "second file" )
这不是一个数组(实际上,可能是单个文件名):
files='"first file" "second file"'
使用"${arrayname[@]}"
展开正确的bash数组以获取所有内容,或"$arrayname"
仅获取第一个条目。
[[ -e $files || -L $files ]]
...因此检查数组中第一个条目的存在(无论是文件还是符号链接) - 这足以判断glob表达式是否实际上是扩展的,或者如果它什么都不匹配。
布尔值更好地用数字值表示,而不是包含true
或false
的字符串:如果if $valid
的内容,则运行valid
有可能执行任意活动可以设置为用户控制的值,而if (( valid ))
- 检查$valid
是否为正数值(true)或其他(false) - 的副作用空间小得多其他地方存在漏洞。
没有必要循环遍历数组条目以在列表中打印它们:printf "$format_string" "${array[@]}"
只要有更多的参数(来自数组扩展)而不是格式字符串需要,就会扩展格式字符串。此外,在格式字符串中使用%q
将引用非打印值,空格,换行符和&amp; c。用于人类读者和shell都可以使用的格式 - 否则用touch $'evil\n - hiding'
创建的文件似乎是两个列表条目,而实际上只有一个。