Если вы спокойно стоите в коридорах Unix и Linux и внимательно слушаете, вы услышите призрачный голос, жалко вопящий: «А как насчет имен файлов, которые содержат переводы строки?»
ls -d *snp* | wc -l
или, что эквивалентно ,
printf "%s\n" *snp* | wc -l
выведет все имена файлов, которые содержат snp, каждое из которых следует за новой строкой,
но также включает любые новые строки в именах файлов , а затем посчитает количество строк в выводе. Если есть файл с именем
f o o
s n p \n
b a r
. t s v
тогда это имя будет записано как
foosnp
bar.tsv
что, конечно, будет засчитываться как две строки.
Есть несколько альтернатив, которые лучше по крайней мере в некоторых случаях:
printf "%s\n" * | grep -c snp
который считает строки, которые содержат snp, так что foosnp(\n)bar.tsvпример сверху считается только один раз. Небольшая разница в этом
ls -f | grep -c snp
Вышеуказанные две команды отличаются тем, что:
ls -fБудет включать в себя файлы, имена которых начинаются с .; printf … *не произойдет , если dotglobпараметр оболочки не установлен.
printfвстроенная оболочка; lsэто внешняя команда. Таким образом, lsможет использовать немного больше ресурсов.
- Когда оболочка обрабатывает a
*, она сортирует имена файлов;
ls -fне сортирует имена файлов. Таким образом, lsможет использовать немного меньше ресурсов.
Но у них есть что-то общее: они оба будут давать неправильные результаты при наличии имен файлов, которые содержат новую строку и имеют snpкак до, так и после новой строки .
Другой:
filenamelist=(*snp*)
echo ${#filenamelist[@]}
Это создает переменную массива оболочки со списком всех имен файлов, которые содержат snp, а затем сообщает количество элементов в массиве. Имена файлов обрабатываются как строки, а не как строки, поэтому встроенные символы новой строки не являются проблемой. Вполне возможно, что этот подход может иметь проблемы, если каталог огромен, потому что список имен файлов должен храниться в памяти оболочки.
Еще один:
Ранее, когда мы говорили printf "%s\n" *snp*, printfкоманда повторяла (повторно использовала) "%s\n"строку формата один раз для каждого аргумента в расширении *snp*. Здесь мы вносим небольшое изменение в это:
printf "%.0s\n" *snp* | wc -l
Это будет повторять (повторно использовать) "%.0s\n"строку формата один раз для каждого аргумента в расширении *snp*. Но "%.0s"означает печатать первые ноль символов каждой строки - т.е. ничего. Эта printfкоманда будет выводить только новую строку (т. Е. Пустую строку) для каждого файла, содержащегося snpв его имени; а потом wc -lбудет их считать. И, опять же, вы можете включить .файлы, установив dotglob.