Проблема с пробелами в именах файлов

Я хочу сделать что-нибудь несколько раз в списке файлов. У файлов в вопросах есть пробелы в их именах:

david@david: ls -l
total 32
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha
-rw-rw-r-- 1 david david  0 Mai  8 11:55 haha~
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (3rd copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (4th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (5th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (6th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (7th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (another copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (copy)

Теперь я хочу описать каждый из этих файлов:

david@david: echo '
for file in $(ls)
do
stat $file
done' | bash

(я использую echo и pipe для написания нескольких -line команды.)

Когда я это делаю, он корректно работает с теми файлами, в именах которых нет пробелов. Но остальные ...

stat: cannot stat ‘(another’: No such file or directory
stat: cannot stat ‘copy)’: No such file or directory

Изменение $(ls) на "$(ls)" или $file на "$file" не работает. Что я могу сделать?

Редактировать:

echo '
for files in *
do
stat "$files"
done' | bash

делает свое дело! Поскольку я новичок в bash, я хочу, чтобы все было как можно проще - поэтому ничего не пытаясь избежать пробелов, или использовать xargs или решение с read -r, хотя они решают проблему.

Как некоторые спрашивают: да, использовать это вместо stat * странно. Но я просто хотел найти общий способ применения одной и той же команды к группе имен файлов в bash, используя цикл for. Таким образом, stat может обозначать gzip, gpg или rm.

8
задан 8 May 2015 в 14:30

7 ответов

Несколько заключают в кавычки из эти echo ', усложняет вещь.

можно просто использовать:

for f in *; do stat -- "$f"; done

, Но также и

stat -- * 

... и если Вы хотите собрать файлы и затем применить команду (почему?) можно пойти с (но быть осторожными с файлом, содержащим новые строки... (1))

for f in *; do echo "$f"; done | xargs stat --

... и если Вы хотите скрытые файлы также, просто использование * .* как шаблон, но тогда помните, что . и .. будет в наборе .

Как в стороне, Вы не должны анализировать ls, производит .

<час>

(1), но если у Вас есть имена файлов с новыми строками, Вы несколько заслуживаете его...;-)

0
ответ дан 8 May 2015 в 14:30

На ноте стороны: можно разделять долго / сложные команды по нескольким строкам путем добавления, что пространство, сопровождаемое обратной косой чертой и ударом, Входит каждый раз, Вы хотите начать писать в новую строку, вместо того, чтобы разветвить несколько процессов при помощи echo [...] | bash; также необходимо включить $file в двойных кавычках, для предотвращения stat от повреждения в случае имен файлов, содержащих пробелы:

for file in $(ls); \
do \
stat "$file"; \
done

Проблема - это $(ls) расширяется до списка имен файлов, содержащих пробелы, и то же произойдет также с "$(ls)".

Даже решая эту проблему, этот метод все еще повредится на именах файлов, содержащих обратные косые черты и на именах файлов, содержащих новые строки (как указано terdon).

Решение для обеих проблем состояло бы в том, чтобы передать вывод по каналу find к a while выполнение цикла read -r так, чтобы, при каждом повторении, read -r сохранит одну строку findвывод в $file:

find . -maxdepth 1 -type f | while read -r file; do \
    stat "$file"; \
done
6
ответ дан 8 May 2015 в 14:30

Используйте старое доброе find, работы со скрытыми файлами, новыми строками и пробелами.

find . -print0 | xargs -I {} -0 stat {}

или любой другой вместо stat

find . -print0 | xargs -I {} -0 file {}
find . -print0 | xargs -I {} -0 cat {}
0
ответ дан 8 May 2015 в 14:30

Как парень R, я уже нашел обходное решение в R:

filenames <- dir(); # reads file names into an array.
                    # It works also recursively
                    # with dir(recursive=TRUE)
for (i in 1:length(filenames)) {
system(     # calls a system function
 paste(     # join stat and the file name
  "stat",
  filenames[i]
 )
)
}

я знаю, это безумно. Я желаю, чтобы вывод ls было бы легче проанализировать... R может иметь дело с пробелами, потому что dir () возвращает заключенное в кавычки символьное значение. Что-либо между кавычками - тогда имя правильного файла с пробелами.

0
ответ дан 8 May 2015 в 14:30

Я столкнулся с другими экземплярами пробельных проблем в для циклов, таким образом, следующее (imo более устойчивый) команда - то, что я обычно использую. Это также соответствует приятно каналам.

$ ls | while read line; do stat "$line"; done;

Вы могли объединить это с grep или использование find вместо этого:

$ find ./ -maxdepth 2 | grep '^\./[/a-z]+ | while read line; do stat "$line"; done;
0
ответ дан 8 May 2015 в 14:30

Этот ответ будет решать проблему парсинга ls и заботиться о клавишах Backspace и новых строках

Попытка это, это решит Вашу проблему с помощью Внутреннего Разделителя полей IFS.

IFS="\n" for f in $(ls); do   stat "$f"; done

, Но также и можно легко решить его без потребности проанализировать вывод ls с помощью

for f in *; do   stat "$f"; done
0
ответ дан 8 May 2015 в 14:30

Вместо этого можно переименовать файлы, заменяющие пространство некоторым другим символом, такие как подчеркивание, таким образом, Вы избавляетесь от этой проблемы:

, Чтобы сделать это легко выполняет команду:

for file in * ; do mv "$f" "${f// /_}" ; done
0
ответ дан 8 May 2015 в 14:30

Другие вопросы по тегам:

Похожие вопросы: