为什么我使用read命令不能达到我的预期?

时间:2009-04-18 19:18:35

标签: unix shell stdin

我在计算机上做了一些破坏,当我使用vezult [1].建议的命令时,我希望单行代码要求删除文件名。但是,它立即删除了我在文件夹中的文件:

> find ./ -type f | while read x; do rm "$x"; done

我希望它等待我输入stdin:s [2]。我无法理解它的行动。 read命令如何工作,以及在哪里使用它?

2 个答案:

答案 0 :(得分:4)

readstdin读取的内容是file1 file2 。当你把它放在管道的末端时,它会从那个管道中读取。

所以你的发现变成了

read

等等; x读取并file1依次替换file2然后 find . -type f ,因此您的循环变为

rm“file1”    rm“file2”

果然,rm的每个文件从当前目录“。”开始。

一些提示。

你不需要“/”。

更好更安全
. /

因为你碰巧键入“.”(即点空格斜杠),find将从当前目录开始,然后从根目录开始。如果拥有正确的权限,该技巧将删除计算机中的每个文件。 “.”已经是目录的名称;你不需要添加斜杠。

find或rm命令将执行此操作

听起来你想要做的就是浏览从当前目录“ find . -type f -exec rm -i {} \; ”开始的所有目录中的所有文件,如果你想要删除它,请让它为ASK它。你可以用

做到这一点
 find . -type f -ok rm  {} \;

 rm -r -i *

根本不需要循环。你也可以

rm -i `find . -type f`

并获得几乎相同的效果,但它也会尝试删除目录。如果目录为空,那甚至可以正常工作。

另一种想法

想想看,除非你有很多文件,你也可以这样做

-i

现在,反引号中的查找将成为命令行中的一堆文件名,rm上的“{{1}}”交互标记将询问是或否。

答案 1 :(得分:3)

查理·马丁给你一个很好的解剖和解释你的具体例子出了什么问题,但没有解决一般问题:

何时应使用read命令?

答案是 - 当你想从某个文件中读取连续的行(很可能是管道中某些先前命令序列的标准输出)时,可能会将这些行分成几个单独的变量。拆分是使用当前值“$IFS”完成的,这通常意味着在空白和制表符上(换行符不在此上下文中计算;它们将行分开)。如果读命令中有多个变量,则第一个字进入第一个变量,第二个进入第二个变量,......,并将行的残余变为最后一个变量。如果只有一个变量,则整行进入该变量。

有很多用途。这是我使用拆分选项的简单脚本之一:

#!/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。循环体处理未记录的数据库(begincommit不起作用),然后运行程序sqlcmd(完全独立于同名的Microsoft新手;自1990年左右开始创建一个数据库并用一些标准表和数据填充它 - 模拟Oracle'dual'表,以及一组与'元素表'相关的表。< / p>

使用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的变体,只匹配整个单词(以避免像'已经'这样的单词)。这给出了我如何使用它的一些指示。

'read x || exit'行用于从标准输入读取响应的交互式脚本,但如果命令获得EOF则退出(例如,如果标准输入来自/dev/null)。