Почему мое использование команды чтения не сделало то, что я ожидал? - PullRequest
0 голосов
/ 18 апреля 2009

Я немного испортил свой компьютер, когда играл с командами, предложенными vezult [1]. Я ожидал, что однострочный запросит удаление имени файла Тем не менее, он немедленно удалил мои файлы в папке:

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

Я ожидал, что это дождется моего ввода stdin: s [2] . Я не могу понять его действие. Как работает команда чтения и где вы ее используете?

Ответы [ 2 ]

4 голосов
/ 18 апреля 2009

То, что произошло, это то, что read читает из stdin. Когда вы помещаете его в конец трубы, он читает из этой трубы.

Итак, ваша находка становится

file1
file2

и т. Д .; read читает это и последовательно заменяет x на file1, затем file2, и ваш цикл становится

rm "file1" рм "файл2"

и достаточно точно, каждый rm файл начинается с текущего каталога ".".

Пара подсказок.

Вам не нужно "/".

Лучше и безопаснее сказать

 find . -type f

, потому что если вы наберете «. /» (то есть, косая черта с пробелом), find начнет с текущего каталога, а затем начнет поиск с корневого каталога. Этот трюк, учитывая правильные привилегии, удалит каждый файл на компьютере . «.» - это уже имя каталога; вам не нужно добавлять косую черту.

Команды find или rm сделают это

Похоже, что хотел сделать, это просмотреть все файлы во всех каталогах, начиная с текущего каталога ".", и попросить его, если вы хотите удалить его. Вы можете сделать это с

 find . -type f -exec rm -i {} \;

или

 find . -type f -ok rm  {} \;

и петля вообще не нужна. Вы также можете сделать

 rm -r -i *

и получите почти тот же эффект, за исключением того, что он также попытается удалить каталоги. Если каталог пуст, это даже сработает.

Еще одна мысль

Если подумать, если у вас много файлов, вы также можете сделать

rm -i `find . -type f`

Теперь поиск в обратных кавычках станет набором имен файлов в командной строке, а интерактивный флаг -i на rm задаст вопрос «да» или «нет».

3 голосов
/ 19 апреля 2009

Чарли Мартин дает вам хорошее объяснение и объяснение того, что пошло не так с вашим конкретным примером, но не отвечает на общий вопрос:

Когда следует использовать команду чтения?

Ответ на этот вопрос таков: когда вы хотите прочитать последовательные строки из какого-либо файла (вполне возможно, стандартный вывод некоторой предыдущей последовательности команд в конвейере), возможно, разбив строки на несколько отдельных переменных. Разделение выполняется с использованием текущего значения '$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

Команда 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, который соответствует только целым словам (чтобы избежать таких слов, как «уже»). Это дает некоторое представление о том, как я его использовал.

Строки 'read x || exit' предназначены для интерактивного сценария, который читает ответ от стандартного ввода, но завершается, если команда получает EOF (например, если стандартный ввод поступает из /dev/null).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...