Bash – dane z pliku lub stdin, przekierowanie wyjścia

Dawno temu napisałem krótki wpis związany z wykrywaniem jak podajemy dane do skryptu Basha. Przydało by się go uzupełnić o sprawdzenie przekierowania stdout i stderr:

#!/bin/bash                                                                                                                                  
set -o nounset

stdin=0
stdout=1
stderr=2

if [[ ( (( $# )) && -f "${1-}" ) || ! -t "$stdin" ]]; then
    if [[ (( $# )) && -f "${1-}" ]]; then
        FILE=$1
        ls -l /dev/fd/$stdin
        echo "Reading from a file"
        while read -r LINE; do
            echo "$LINE"
        done < "$FILE"
    fi
    if [ ! -t $stdin ]; then
        ls -l /dev/fd/$stdin
        echo "Reading from stdin"
        while read -r LINE; do
            echo "$LINE"
        done
    fi
else
    echo "No data provided"
fi

if [[ ! -t "$stdout" ]]; then
    echo "Stdout redirected via '>' or '| tee'"
    ls -l /dev/fd/$stdout
elif [[ -t "$stdout" ]]; then
    echo "Writing on stdout"
    ls -l /dev/fd/$stdout
fi

if [[ ! -t "$stderr" ]]; then
    echo "Stderr redirected via '2>' or '2> >(tee )'"
    echo "Stderr redirected via '2>' or '2> >(tee )'" >&2
    ls -l /dev/fd/$stderr
    ls -l /dev/fd/$stderr >&2
fi

System UIDs inconsistent

mosnter-uids

System UIDs inconsistent

UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.

Przy uruchomieniu telefonu przywitał mnie taki komunikat. Czyszczenie partycji data nie było brane pod uwagę.

Znalazłem informację żeby sprawdzić zawartość /data/system/uiderrors.txt. U mnie było:

11.10.2016 21:14: Package de.robv.android.xposed.installer has mismatched uid: 10075 on disk, 10142 in settings

Odinstalowałem więc aplikację:

root@Pentagram:/data/app # pm uninstall de.robv.android.xposed.installer
Success

Z poziomu samego telefonu nie mogłem tego zrobić. Aczkolwiek pewnie może by się dało bez odinstalowania ale już po fakcie.

Unicode Byte Order Mark (BOM)

Rozpoznanie BOM w zależności od kodowania:

Bytes         | Encoding Form 
--------------+------------------------
00 00 FE FF   | UTF-32, big-endian 
FF FE 00 00   | UTF-32, little-endian 
FE FF         | UTF-16, big-endian 
FF FE         | UTF-16, little-endian 
EF BB BF      | UTF-8 

Wykrycie BOM:

`xxd -l 3 -p filename` == efbbbf

cdn.

Android – „out of space” podczas instalacji pakietu

Krótkie wprowadzenie:
Aktualnie jestem w posiadaniu telefonu Pentagram Monster X5 Pro. Wybrałem go ze względu na dużą baterię 6000mAh. Z czasem jednak okazało się że telefon nie jest idealny, system od producenta nieaktualizowany a ciągłe zwiechy bywają uciążliwe. Dlatego aktualnie testuję inne ROMy i a na tą chwilę sprawdzam CyanogenMod 11.Do kopii ustawień jak i samych pakietów używam Super Backup.

Jednak ostatnio nie mogłem przywrócić wszystkich aplikacji np Smart AudioBook Player. Podczas instalacji czy to z poziomu SuperBackup czy sklepu dostawałem informację o zbyt małej ilości wolnego miejsca na urządzeniu.

Z poziomu adb komunikat był trochę inny:

adb install 'Smart AudioBook Player_3.1.3.apk'
[100%] /data/local/tmp/Smart AudioBook Player_3.1.3.apk
    pkg: /data/local/tmp/Smart AudioBook Player_3.1.3.apk
Failure [INSTALL_FAILED_INSUFFICIENT_STORAGE]

Po wejściu na urządzenie do /data/app było widać że apka jest zainstalowana. W końcowym rezultacie musiałem wykasować z dwóch katalogów pliki związane z tą apką:

  • /data/app/
  • /data/app-lib/
  • /data/data

Na razie podejrzewam problem z CM11 który niestety nie działa idealnie ale w porównaniu z CM12.1 i CM13 na Pentagramie zdecydowanie lepiej.

cd.

W końcowym rezultacie przywróciłem oryginalny ROM i na nim także miałem problem z zainstalowaniem apki, ale pomogła ręczna instalacja:

adb shell
...
pm install ADWLauncher\ EX_1.3.3.9.apk

cd.

Podobny przypadek wystąpi gdy mamy aplikacje przeniesione na kartę SD za pomocą np. Link2SD, które zostaną skasowane z karty. W systemie wówczas wiszę zepsute symlinki których standardowy instalator nie potrafi nadpisać, skasować.

Przekierowanie w potoku do kilku komend

Miałem potrzebę przefiltrowania wyniku jakiegoś polecenia w osobnych niezależnych komendach. Najprostszy przykład:

(echo yes; echo or; echo no; ) | grep -e no -e yes -
yes
no

Jednak jeśli musimy coś zrobić z tymi danymi wówczas trzeba sobie pomóc programem tee:

(echo yes; echo or; echo no; ) | tee >(grep yes) >(grep no) 1>/dev/null
yes
no

Bez przekierowania STDOUT na /dev/null dodatkowo na wyjściu dostaniemy powielone wejście.

c.d.
Dodatkowo można np. wyświetlić wynik jakieś komendy i od razu np. zliczyć słowa itp:

cat /etc/passwd | tee >(wc)

[Perl]Defined vs exists vs …

#!/usr/bin/env perl

use strict;
use warnings;
use Data::Dumper;
use feature qw(say);

my $hash = {
    zero  => 0,
    one   => 1,
    two   => 'two',
    three => undef,
};

print Dumper $hash;

say "\nTesting defined";
for my $key ( keys %$hash ) {
    if ( defined  $hash->{$key} ) {
        say "'defined $hash->{$key}'";
    }
    else {
        say "'not defined for $key'";
    }
}
if ( defined $hash->{four} ){
    say "'defined for key four'";
}
else {
    say "'not defined for key four'";
}

say "\nTesting exists";
for my $key ( keys %$hash ) {
    if ( exists $hash->{$key} ) {
        say "'exists $hash->{$key}'";
    }
    else {
        say "'not exists for $key'";
    }
}
if ( exists $hash->{four} ){
    say "'exists for key four'";
}
else {
    say "'not exists for key four'";
}

say "\nTesting value";
for my $key ( keys %$hash ) {
    if ( $hash->{$key} ) {
        say "'true value $hash->{$key}'";
    }
    else {
        say "'false value for $key'";
    }
}
if ( $hash->{four} ){
    say "'true value for key four'";
}
else {
    say "'false value for key four'";
}

I wynik:

$ ./defined_exists.pl
$VAR1 = {
          'three' => undef,
          'zero' => 0,
          'one' => 1,
          'two' => 'two'
        };

Testing defined
'not defined for three'
'defined 0'
'defined 1'
'defined two'
'not defined for key four'

Testing exists
Use of uninitialized value in concatenation (.) or string at ./defined_exists.pl line 35.
'exists '
'exists 0'
'exists 1'
'exists two'
'not exists for key four'

Testing value
'false value for three'
'false value for zero'
'true value 1'
'true value two'
'false value for key four'

[perl]Pseudo statyczne pole

package Foo;
use strict;
use warnings;
my $version = '0.0';
use fields qw(version);
sub setVersion {
    my $self = shift;
    ${$self->{version}} = $_[0];
}
sub getVersion {
    my $self = shift;
    return ${$self->{version}};
}
sub new {
    my $self = shift;
    unless (ref $self) { 
        $self = fields::new($self);
    } 
    $self->{version} = \$version;
    return $self;
}
1;

Dla powyższego przykładu pole version będzie statyczne. Dla każdego kolejnego obiektu będzie jedna wartość dla version.

use Foo;

my $foo = Foo->new();
print $foo->getVersion(), "\n";
$foo->setVersion("1.0");
print $foo->getVersion(), "\n";

my $bar = Foo->new();
print $bar->getVersion(), "\n";

Efekt powyższego:

0.0
1.0
1.0

No such pseudo-hash field „…” at

Pracując na starym Perl (<=5.8.9) z modułem (fields) miałem dziwny przypadek że pola z pakietu nadrzędnego nie były dostępne dla pakietu pochodnego.

 $ ./script.pl
No such pseudo-hash field "version" at lib/Foo.pm line 24.

A wystarczyło użyć tylko base zamiast parent. Więcej tutaj.

Poza tym parent ma jeszcze jedno "ograniczenie". Jeśli zagnieździmy moduł w tym samym pliku to przy użyciu:

{
    package Bar;
    use parent 'Foo';
    ...
 $ ./script.pl 
Can't locate Foo.pm in @INC (@INC contains ...

Całość przykładu na github:

 $ ./script.pl
$VAR1 = bless( [
                 bless( {
                          'version' => 1,
                          'release' => 2
                        }, 'pseudohash' ),
                 undef,
                 '12345'
               ], 'BarBase' );
$VAR1 = bless( [
                 bless( {
                          'release' => 1
                        }, 'pseudohash' ),
                 '12345'
               ], 'BarParent' );

compgen i bash-completion

compgen

Parametry wypisujące

  • -a – wypisuje aliasy, (eng. aliases)
  • -b – wbudowane polecenia (built-ins)
  • -c – wszystkie komendy, razem z wbudowanymi (commands)
  • -d – katalogi (directories)
  • -e – zmienne środowiskowe (env)
  • -f – pliki (files) i katalogi
  • -g – grupy (groups)
  • -j – zadania w tle (jobs)
  • -k – słowa kluczowe powłoki (keywords)
  • -s – ? ()
  • -u – użytkownicy (users)
  • -v – ? ()

Dalsze parametry

  • -o opcja – ?
  • -A akcja, gdzie akcja to:
alias      binding    command    disabled   export     function   helptopic  job        running    setopt     signal     user       
arrayvar   builtin    directory  enabled    file       group      hostname   keyword    service    shopt      stopped    variable
  • -G wzorzec
  • -W lista słów do uzupełnienia
  • -F funkcja

bash-completion

Domyślne funkcje

Wraz z bash-completion dostarczone są pewne domyślne funkcje:
* _init_completion –
* _get_comp_words_by_ref [zmienne lokalne] –

Zmienne

  • COMPREPLY – tablica uzupełnień
  • COMP_CWORD – poziom uzupełnień, indeks w tablicy COMP_WORDS, poziomy to kolejne opcje/parametry dla polecenia
  • COMP_WORDS – tablica z aktualnym i poprzednimi słowami dla komendy, zamiast tego używaj _get_comp_words_by_ref

complete czyli uzupełnianie

Najlepiej na przykładzie:

_firefox() {
    local cur 
    _get_comp_words_by_ref cur 
    COMPREPLY=()
    opts=$(_parse_help $1 --help)
    COMPREPLY=( $(compgen -W "$opts" -- "$cur") )
} 
complete -F _firefox firefox

cdn.

[Archlinux]Rozmiar zainstalowanych pakietów

Potrzebowałem wiedzieć ile zajmują zainstalowane pakiety w systemie. W sieci znalazłem skrypt który niestety aktualnie nie działa więc napisałem go na nowo ale w Perlu.
Skrypt dostępny jest w serwisie GitHub, zapraszam.