Для цикла с использованием недостатков поиска неправильно обрабатываются имена каталогов с символом пробела - PullRequest
5 голосов
/ 27 июня 2009

Ну, я действительно застрял в этом.

У меня есть файл dirs.txt, который выглядит следующим образом:

/var/tmp/old files.txt
/var/tmp/old backups.bak

Файл dirs.txt создается самим сценарием.

Когда я хочу использовать dirs.txt в цикле for, например:

for dir in `cat dirs.txt` ; do 
    ls -al $dir
done

Вот что выдает команда: ls: невозможно получить доступ к / var / tmp / old: нет такого файла или каталога

Я хочу, чтобы все имена файлов были ls -al'ed, но он пытается ls -al / var / tmp / old

Как я могу исправить это из цикла for?

Ответы [ 2 ]

12 голосов
/ 27 июня 2009
cat dirs.txt | while read dir; do
    ls -al "$dir"
done
  1. Когда вы используете оператор backtick, выходные данные разбиваются на токены для каждого символа пробела. read, с другой стороны, будет читать по одной строке за раз, а не по одному слову за раз. Таким образом, решение, которое выглядит довольно странно, состоит в том, чтобы передать файл в цикл, чтобы его можно было читать построчно.

  2. Вам необходимо указать "$dir" в команде ls, чтобы все имя файла, пробел и все обрабатывалось как один аргумент. Если вы этого не сделаете, ls увидит два имени файла, /var/tmp/old и files.txt.

Я, вероятно, получу премию Бесполезное использование кошки . Вы можете упростить это еще больше, удалив cat:

while read dir; do
    ls -al "$dir"
done < dirs.txt

Это работает, потому что цикл весь while действует как одна большая команда, поэтому точно так же, как вы можете передать cat в нее, вы также можете использовать перенаправление файлов.


Еще дальше ...

В зависимости от того, как генерируется dirs.txt, вы можете просто полностью избавиться от него и сделать все одной командой. Если это просто временный файл, вы можете удалить его, отправив команду, генерирующую dirs.txt в цикл while, пропуская временный файл. Например, заменить

find /var -name '*old*' > dirs.txt
while read dir; do
    ls -al "$dir"
done < dirs.txt

с

find /var -name '*old*' | while read dir; do
    ls -al "$dir"
done

Притворись find - это любая команда, которую ты делаешь для создания списка файлов.

И на самом деле, если вы на самом деле используете find, вы, вероятно, можете сделать все одной большой командой find без каких-либо циклов или чего-либо еще! Например, приведенный выше код с использованием find и while можно выполнить с помощью одной команды find, например:

find /var -name '*old*' -exec ls -al {} \;

find - это действительно гибкая команда, которая может как искать файлы, соответствующие всем видам сложных критериев, так и передавать эти файлы в качестве аргументов командной строки другим командам, используя параметр -exec. При использовании -exec {} заменяется каждым именем файла.

0 голосов
/ 04 мая 2011

У меня была похожая проблема, когда я пытался разархивировать много файлов в каталоге. Я обнаружил, что, поскольку у меня был псевдоним "ls", я причинял себе ненужное горе. Как только я полностью определил «ls» как «/ bin / ls», все стало хорошо с миром.

Однако, что касается вашей конкретной проблемы, я не понимаю, зачем вам нужен файл после имени каталога, когда вам может потребоваться косая черта между ними (т. Е. /Var/tmp/old/files.txt).

Однако тот факт, что вы хотите выполнить "ls -al", тоже не подходит. Казалось бы, в конечном итоге вы выполняете много «ls -al / var / tmp / old» (по одной на запись в dirs.txt), а затем длинный список каждого локального файла с именем, как вы показали, файлы .txt и backups.bak.

Поскольку этой теме уже почти 2 года, я полагаю, что вы уже давно преодолели эту проблему:)

...