grep początek pliku?

10

W powłoce linuksa chcę się upewnić, że cały zestaw plików zaczyna się od tego <?, że ma dokładnie ten ciąg i nie ma innych znaków na początku. Jak mogę grepować lub użyć innego wyrażenia „plik zaczyna się od”?


Edycja: używam symboli wieloznacznych i headnie podam nazwy pliku w tym samym wierszu, więc kiedy grep go, nie widzę nazwy pliku. Ponadto "^<?"nie wydaje się dawać właściwych rezultatów; w zasadzie otrzymuję to:

$> head -1 * | grep "^<?"
<?
<?
<?
<?
<?
...

Wszystkie pliki są w rzeczywistości dobre.

użytkownik13743
źródło

Odpowiedzi:

11

W Bash:

for file in *; do [[ "$(head -1 "$file")" =~ ^\<\? ]] || echo "$file"; done

Upewnij się, że są to pliki:

for file in *; do [ -f "$file" ] || continue; [[ "$(head -1 "$file")" =~ ^\<\? ]] || echo "$file"; done

janmoesen
źródło
a ponieważ wszyscy jesteśmy pedantyczni: nie używaj operatora globalnego do ogromnej liczby nazw plików, zamiast tego używajfind
akira
użycie findmoże również zwrócić tylko zwykłe pliki bezpośrednio do uruchomienia potoku.
mpez0
1
Możesz także zrobić to całkowicie w Bash, używając readzamiast head: for file in *; do [ -f "$file" ] || continue; read < "$file"; [[ "$REPLY" =~ ^\<\? ]] || echo "$file"; done
janmoesen
4

Wykonaj grep:

$ head -n 1 * | grep -B1 "^<?"
==> foo <==
<?
--
==> bar <==
<?
--
==> baz <==
<?

Parsuj nazwy plików:

$ head -n 1 * | grep -B1 "^<?" | sed -n 's/^==> \(.*\) <==$/\1/p'
foo
bar
baz
Wstrzymano do odwołania.
źródło
3

Możesz użyć do tego 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
$
hlovdal
źródło
3

Z wyjątkiem pustych plików ten skrypt Perla wydaje się działać:

perl -e 'while (<>) { print "$ARGV\n" unless m/^<\?/; close ARGV; }' *

Nie jestem od razu pewien, jak obsługiwać puste pliki; Skusiłbym się potraktować je jako osobny przypadek szczególny:

find . -type f -size +0 -print0 |
    xargs -0 perl -e 'while (<>) { print "$ARGV\n" unless m/^<\?/; close ARGV; }'
Jonathan Leffler
źródło
2

Spróbuj tego

for i in `find * | grep "php$"`; do echo -n $i " -> "; head -1 $i; done

Spowoduje to wyświetlenie listy każdego pliku kończącego się na PHP, a następnie przechodzenie przez niego. echo nazwy pliku, a następnie wydrukowanie pierwszego wiersza pliku. Właśnie włożyłem

da ci dane wyjściowe takie jak:

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

możesz na końcu przykleić normalny grep, aby pozbyć się tego, co chcesz zobaczyć i znaleźć tylko wyjątki

for i in `find * | grep "php$"`; do echo -n $i " -> "; head -1 $i; done | grep -v "<?php"

wynik:

gallery.php  ->
splash.php  -> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
Roy Rico
źródło
4
Bezużyteczne użycie grep; użyj „find -name” * .php ”. Niebezpieczne użycie zmiennych: użyj polecenia „find -exec tutaj” {} „+”, aby uniknąć problemów ze „specjalnymi” nazwami plików. Poza tym zawsze podawaj swoje zmienne: „głowa -1” $ i ”, a nie„ głowa -1 $ i ”.
janmoesen
for x in *.php;do echo $x \"głowa -n1 $ x\";done
użytkownik23307
1

Bash 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
użytkownik31894
źródło
0
cat file.txt | head -1 | grep "^<?"

powinien zrobić to, o co prosisz.

Phoshi
źródło
Tak, ale jeśli go użyję, nie otrzymam nazw plików :( Również „^ <?” Nie działało dla mnie, użyłem przełącznika -v.
user13743
2
@ Phoshi Kompulsywne catużycie, head -1 file.txt | grep "^<?"wystarczy.
Benjamin Bannier,
1
Bezużyteczne użycie kota: - (((
vwegert
Bezużyteczny kot jest bezużyteczny :(
user13743,
Uważam, że łatwiej jest zapamiętać polecenia, jeśli wszystko jest modułowe i zepsute. Wiem, kot będzie działał, nie wiem, czy commandpotraktuje plik jako argument. Może nie jest to absolutnie konieczne, ale nie
wyjmuję
0

to:

  % for i in *; do head -1 $i | grep "^<?" ; echo "$i : $?"; done

daje ci coś takiego:

  foo.xml: 0
  bla.txt: 1

każdy plik niezawierający wzorca będzie „oznaczony” „1”. możesz z tym grać, dopóki nie spełni twoich potrzeb.

akira
źródło
1
Musisz podać nazwy plików, jeśli mogą zawierać spacje. I prawdopodobnie chciałbyś stracić wyjście z 'grep' na / dev / null. Możesz także użyć:, head -1 "$i" | grep '^<?' || echo "$i"która wypisze nazwę pliku tylko wtedy, gdy jest problematyczna.
Jonathan Leffler,
2
Po to jest „grep -q”. :-)
janmoesen
0

Pozwól mi spróbować

znajdź -type f | awk
{
 if (getline ret <0 $) {
  if (ret ~ "^ <\\? $") {
   drukuj „Dobry [„ $ 0 ”] [„ ret ”]”;
  }jeszcze{
   drukuj „Fail [„ $ 0 ”]”;
  };
 }jeszcze{
  print „pusty [„ 0 USD ”]”;
 };
 zamknij (0 USD);
} ”

nikt nie powiedział, że wak był niedostępny :-)

użytkownik42723
źródło