grep начало файла?
В оболочке Linux я хочу убедиться, что определенный набор файлов начинается с <?
, имея эту точную строку и никаких других символов в начале. Как я могу использовать grep или использовать другое выражение для выражения "файл начинается с"?
Редактировать: я подстановочный знак, и head
не дает имя файла в той же строке, поэтому, когда я grep это, я не вижу имя файла. Также, "^<?"
кажется, не дает правильных результатов; в основном я получаю это:
$> head -1 * | grep "^<?"
<?
<?
<?
<?
<?
...
Все файлы действительно хороши.
11 ответов
В Баш:
for file in *; do [[ "$(head -1 "$file")" =~ ^\<\? ]] || echo "$file"; done
Убедитесь, что они являются файлами:
for file in *; do [ -f "$file" ] || continue; [[ "$(head -1 "$file")" =~ ^\<\? ]] || echo "$file"; done
Сделать grep
:
$ head -n 1 * | grep -B1 "^<?"
==> foo <==
<?
--
==> bar <==
<?
--
==> baz <==
<?
Разобрать имена файлов:
$ head -n 1 * | grep -B1 "^<?" | sed -n 's/^==> \(.*\) <==$/\1/p'
foo
bar
baz
За исключением пустых файлов, этот скрипт на Perl работает:
perl -e 'while (<>) { print "$ARGV\n" unless m/^<\?/; close ARGV; }' *
Я не сразу уверен, как обращаться с пустыми файлами; Я хотел бы рассматривать их как отдельный особый случай:
find . -type f -size +0 -print0 |
xargs -0 perl -e 'while (<>) { print "$ARGV\n" unless m/^<\?/; close ARGV; }'
Вы можете использовать awk для этого:
$ cat test1
<?xxx>
111
222
333
$ cat test2
qqq
aaa
zzz
$ awk '/^<\?/{print "Starting with \"<?\":\t" ARGV[ARGIND]; nextfile} {print "Not starting with \"<?\":\t" ARGV[ARGIND]; nextfile}' *
Starting with "<?": test1
Not starting with "<?": test2
$
Попробуй это
for i in `find * | grep "php$"`; do echo -n $i " -> "; head -1 $i; done
Это получит список каждого файла, оканчивающегося на PHP, а затем цикл по нему. повторяя имя файла и затем печатая первую строку файла. Я только что вставил
даст вам вывод, как:
calendar.php -> <?php
error.php -> <?php
events.php -> <?php
gallery.php ->
index.php -> <?php
splash.php -> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
information.php -> <?php
location.php -> <?php
menu.php -> <?php
res.php -> <?php
blah.php -> <?php
тогда вы можете вставить обычный grep в конце, чтобы избавиться от того, что вы хотите увидеть, и найти только исключения
for i in `find * | grep "php$"`; do echo -n $i " -> "; head -1 $i; done | grep -v "<?php"
выход:
gallery.php ->
splash.php -> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
Баш 4.0
#!/bin/bash
shopt -s globstar
for php file in /path/**/*.php
do
exec 4<"$php";read line <&4;exec 4<&-
case "$line" in
"<?"*) echo "found: $php"
esac
done
Поскольку вы пытаетесь найти только файлы, которые не начинаются с поискового запроса, я рекомендую использовать grep с командой-v
вариант.
В этом примере я использовал grep рекурсивно и позволил ему печатать номера строк, передавать выходные данные второму экземпляру grep, который соответствует номеру строки 1, за которым следует строка поиска:
╰─$ grep -nr "." | grep -v "1:<?"
foo/16:1:a<?
asdf/16:1:a<?
11:1:<a?
16:1:a<?
Как вы можете видеть, результат будет состоять изfilepath:line:match
. Мы можем использовать некоторыеsed
магия, чтобы просто вывести путь к файлам:
╰─$ grep -nr "." | grep -v "1:<?" | sed -E 's/(.+?):1:.*/.\/\1/'
./foo/16
./asdf/16
./11
./16
Позвольте мне попробовать это
найти -тип f | awk ' { if(getline ret <$ 0) { если (в отставке ~ "^ <\\? $") { print "Good [" $ 0 "] [" ret "]"; } Еще { print "Fail [" $ 0 "]"; }; } Еще { print "empty [" $ 0 "]"; }; близко ($ 0); }"
никто не сказал, что Вак не было доступно:-)
cat file.txt | head -1 | grep "^<?"
должен делать то, что вы просите.
Этот :
% for i in *; do head -1 $i | grep "^<?" ; echo "$i : $?"; done
дает вам что-то вроде этого:
foo.xml: 0
bla.txt: 1
каждый файл, не содержащий ваш шаблон, будет помечен "1". Вы можете играть с этим, пока он не соответствует вашим потребностям.
РЕДАКТИРОВАТЬ: как отметил @AdamMierzwiak, это решение не отвечает на вопрос ОП. (он соответствует всем файлам, имеющим ЛЮБУЮ строку, начинающуюся с <?)
grep -lG "^<?" *
объяснение:
-l, --files-with-matches
Suppress normal output; instead print the name of each input
file from which output would normally have been printed. The
scanning will stop on the first match. (-l is specified by POSIX.)
см. эту ссылку для объяснения команды: https://explainshell.com/explain?cmd=grep+-lG+%22%5E%3C%3F%22+*