Shell 脚本,删除文件而不给出整个名称作为参数
Shell Scripting, remove a file without giving the entire name as a parameter
假设我们有一个名为 randomfile_a434534_Frank.csv
的文件
我希望用户输入第一部分 "randomfile*" 作为参数而不是全部。我如何能够 access/say 删除这个特定文件而不指定整个文件名
以下重新提示,直到给出仅匹配单个文件的前缀。根据口味修改——如果你只想测试一次,请删除循环,如果你想从命令行获取前缀,请参考 </code>,或者在多个文件的情况下迭代 <code>"${files[@]}"
如果您的意图是匹配而不是 bailing/reprompting。
#!/bin/bash
# note that the above is necessary to enable features such as arrays; shells started
# with #!/bin/sh may not provide them.
while :; do
echo "Please enter a filename prefix:" >&2
IFS= read -r filename
files=( "$filename"* )
if (( ${#files[@]} == 1 )) && [[ -e "$files" ]]; then
echo "OK; using $files" >&2
break
elif [[ ! -e "$files" ]] || (( ${#files[@]} == 0 )); then
echo "Error: No matching files found" >&2
else
echo "Error: More than one file matches that prefix" >&2
fi
done
echo "Operating on file named: $files"
您可以只使用 rm "$intput"*
的用户输入(或者 -i 如果您希望用户检查哪些文件正在被删除)但要注意实际的用户输入,这可能会使您的脚本出现意外maner.
这是一个小的 shell 概念证明:
$ touch aaJKL
$ toto=aa
$ rm -i "$toto"* # thanks Charles Duffy
rm: remove regular empty file `aaJKL'? y
会发生什么?
- 用户提供../../../path/to/sensitive/file
用户提供./; <<nasty command>>; echo "
并执行任意命令正如Charles所指出的,这种漏洞只发生在字符串替换before shell 执行语法解析(例如生成要传递给 system()
的字符串时,或者当 eval
用于强制执行额外的解析传递时)。
- 用户使用符号 link 指向另一个文件
另一个提示是向用户提示一个 inode 号,并确保这个 inode 号是合法的。
例如,您可以这样做:
#!/usr/bin/env bash
echo "Choose a single file number you want to remove"
ls -i1 ./
read filenumber
if [[ $filenumber =~ ^[-+]?[0-9]+$ ]]; then
find . -inum $filenumber -delete
else
echo "Expect integer as an input"
fi
示例输出:
$ touch sample{1,2,3,4}
$ ./so.sh
Choose a single file number you want to remove
1614159 sample1
1614160 sample2
1614161 sample3
1614162 sample4
fds
Expect integer as an input
$ ./so.sh
Choose a single file number you want to remove
1614159 sample1
1614160 sample2
1614161 sample3
1614162 sample4
1614159
$ ./so.sh # notice that sample1 was deleted
Choose a single file number you want to remove
1614160 sample2
1614161 sample3
1614162 sample4
假设我们有一个名为 randomfile_a434534_Frank.csv
的文件我希望用户输入第一部分 "randomfile*" 作为参数而不是全部。我如何能够 access/say 删除这个特定文件而不指定整个文件名
以下重新提示,直到给出仅匹配单个文件的前缀。根据口味修改——如果你只想测试一次,请删除循环,如果你想从命令行获取前缀,请参考 </code>,或者在多个文件的情况下迭代 <code>"${files[@]}"
如果您的意图是匹配而不是 bailing/reprompting。
#!/bin/bash
# note that the above is necessary to enable features such as arrays; shells started
# with #!/bin/sh may not provide them.
while :; do
echo "Please enter a filename prefix:" >&2
IFS= read -r filename
files=( "$filename"* )
if (( ${#files[@]} == 1 )) && [[ -e "$files" ]]; then
echo "OK; using $files" >&2
break
elif [[ ! -e "$files" ]] || (( ${#files[@]} == 0 )); then
echo "Error: No matching files found" >&2
else
echo "Error: More than one file matches that prefix" >&2
fi
done
echo "Operating on file named: $files"
您可以只使用 rm "$intput"*
的用户输入(或者 -i 如果您希望用户检查哪些文件正在被删除)但要注意实际的用户输入,这可能会使您的脚本出现意外maner.
这是一个小的 shell 概念证明:
$ touch aaJKL
$ toto=aa
$ rm -i "$toto"* # thanks Charles Duffy
rm: remove regular empty file `aaJKL'? y
会发生什么?
- 用户提供../../../path/to/sensitive/file
用户提供正如Charles所指出的,这种漏洞只发生在字符串替换before shell 执行语法解析(例如生成要传递给./; <<nasty command>>; echo "
并执行任意命令system()
的字符串时,或者当eval
用于强制执行额外的解析传递时)。- 用户使用符号 link 指向另一个文件
另一个提示是向用户提示一个 inode 号,并确保这个 inode 号是合法的。
例如,您可以这样做:
#!/usr/bin/env bash
echo "Choose a single file number you want to remove"
ls -i1 ./
read filenumber
if [[ $filenumber =~ ^[-+]?[0-9]+$ ]]; then
find . -inum $filenumber -delete
else
echo "Expect integer as an input"
fi
示例输出:
$ touch sample{1,2,3,4}
$ ./so.sh
Choose a single file number you want to remove
1614159 sample1
1614160 sample2
1614161 sample3
1614162 sample4
fds
Expect integer as an input
$ ./so.sh
Choose a single file number you want to remove
1614159 sample1
1614160 sample2
1614161 sample3
1614162 sample4
1614159
$ ./so.sh # notice that sample1 was deleted
Choose a single file number you want to remove
1614160 sample2
1614161 sample3
1614162 sample4