当我使用 vezult [1] 建议的命令时,我对我的计算机造成了一些破坏。我希望单线器要求删除文件名。但是,它立即删除了我在文件夹中的文件:
> find ./ -type f | while read x; do rm "$x"; done
我希望它等待我输入 stdin:s [2]。我无法理解它的动作。读取命令是如何工作的,你在哪里使用它?
当我使用 vezult [1] 建议的命令时,我对我的计算机造成了一些破坏。我希望单线器要求删除文件名。但是,它立即删除了我在文件夹中的文件:
> find ./ -type f | while read x; do rm "$x"; done
我希望它等待我输入 stdin:s [2]。我无法理解它的动作。读取命令是如何工作的,你在哪里使用它?
那里发生的事情是read
从stdin
. 当您将它放在管道的末端时,它会从该管道读取。
所以你的发现变成了
file1
file2
等等; read
读取它并用thenx
连续替换,因此您的循环变为file1
file2
rm“文件1” rm“文件2”
果然,rm 的每个文件都从当前目录“.”开始。
几个提示。
您不需要“/”。说得更好更安全
find . -type f
因为如果您碰巧键入“ . /
”(即点空格斜杠),find 将从当前目录开始,然后从根目录开始查找。如果有适当的权限,这个技巧会删除计算机中的每个文件。“ .
”已经是一个目录的名称;你不需要添加斜线。
听起来您想要做的是浏览从当前目录“ .
”开始的所有目录中的所有文件,并询问是否要删除它。你可以这样做
find . -type f -exec rm -i {} \;
或者
find . -type f -ok rm {} \;
并且根本不需要循环。你也可以做
rm -r -i *
并获得几乎相同的效果,除了它也会尝试删除目录。如果目录为空,那甚至可以工作。
另一个想法想想看,除非你有很多文件,否则你也可以这样做
rm -i `find . -type f`
现在反引号中的查找将成为命令行上的一堆文件名,并且' -i
'交互式标志rm
将询问是或否问题。
查理·马丁(Charlie Martin)对您的具体示例出了什么问题进行了很好的剖析和解释,但没有解决以下一般问题:
答案是 - 当您想从某个文件中读取连续的行(很可能是管道中某些先前命令序列的标准输出)时,可能会将这些行拆分为几个单独的变量。拆分是使用 ' $IFS
' 的当前值完成的,这通常意味着在空白和制表符上(在这种情况下,换行符不计算在内;它们分隔行)。如果读取命令中有多个变量,则第一个单词进入第一个变量,第二个进入第二个,...,并且该行的剩余部分进入最后一个变量。如果只有一个变量,则整行都进入该变量。
有很多用途。这是我拥有的使用 split 选项的更简单的脚本之一:
#!/bin/ksh
#
# @(#)$Id: mkdbs.sh,v 1.4 2008/10/12 02:41:42 jleffler Exp $
#
# Create basic set of databases
MKDUAL=$HOME/bin/mkdual.sql
ELEMENTS=$HOME/src/sqltools/SQL/elements.sql
cat <<! |
mode_ansi with log mode ansi
logged with buffered log
unlogged
stores with buffered log
!
while read dbs logging
do
if [ "$dbs" = "unlogged" ]
then bw=""; cw=""
else bw="-ebegin"; cw="-ecommit"
fi
sqlcmd -xe "create database $dbs $logging" \
$bw -e "grant resource to public" -f $MKDUAL -f $ELEMENTS $cw
done
带有 here-document的cat
命令将其输出发送到管道,因此输出进入while read dbs logging
循环。第一个词进入$dbs
并且是我要创建的(Informix)数据库的名称。该行的其余部分被放入 $logging。循环的主体处理未记录的数据库(在哪里begin
和commit
不工作),然后运行一个程序sqlcmd
(与同名的 Microsoft 新来者完全分开;它自 1990 年左右就存在)创建一个数据库并填充它一些标准的表和数据——Oracle ' dual
' 表的模拟,以及一组与“元素表”相关的表。
使用该read
命令的其他脚本更大(到目前为止),但通常读取包含一个或多个文件名和一些其他相关属性的行,然后使用这些属性对文件应用适当的转换。
Osiris JL: file * | grep 'sh.*script' | sed 's/:.*//' | xargs wgrep read
esqlcver:read version letter
jlss: while read directory
jlss: read x || exit
jlss: read x || exit
jlss: while read file type link owner group perms
jlss: read x || exit
jlss: while read file type link owner group perms
kb: while read size name
mkbod: while read directory
mkbod:while read dist comp
mkdbs:while read dbs logging
mkmsd:while read msdfile master
mknmd:while read gfile sfile version notes
publictimestamp:while read name type title
publictimestamp:while read name type title
Osiris JL:
'Osiris JL:' 是我的命令行提示符;我在我的“bin”目录中运行了这个。' wgrep
' 是 grep 的变体,它只匹配整个单词(避免使用像 'already' 这样的单词)。这说明了我是如何使用它的。
' read x || exit
' 行用于从标准输入读取响应的交互式脚本,但如果命令获取 EOF(例如,如果标准输入来自/dev/null
)则退出。