Ziŝaj Konsiletoj 4-a: Ĝeneralhelpiloj

Esperanto┃English
Laste ĝisdatigita: la 19-an de marto 2022

Vidpunkto meritas okdek poentojn da inteligentecaj kvocientoj.
—Alan KAY

adam-hornyak-Cm187aESg0k-unsplash

Enhavotabelo

Enkonduko

Lastfoje, mi parolis pri la helpilaj funkcioj por asisti en la mastrumado de radikigmedioj. En ĉi tiu artikolo, mi parolos pri ĝeneralaj helpiloj por labori ĉe la komandlinio. Mi ankaŭ parolos pri helpemaj klavkombinoj por maŝinskribadon plirapidigi.

Funkcioj

Bela afero pri funkcioj, estas, ke ili estas tiom facile por skribi kaj uzi. Jen kelkaj funkcioj kiujn mi uzas ofte.

map

Kiam komandon kiu nur unu argumenton akceptas oni havas, plurajn uzojn de tiu komando oni volas simuli per ĉi tiu funkcio. Ĝi estas difinita jene:

function map () {
  for i (${argv[2,-1]}) { ${(ps: :)${1}} $i }
}

Ekzemple, je map oni povas uzi por plurajn gitaj deponejon, serie:

% map 'git clone' git@github.com:nixos/nixpkgs.git git@github.com:tmux/tmux.git

rmap

Kiel la nomo implicas, rmap funkcias kiel la inverso de map—la cetaraj argumentoj estas aplikitaj kiel komandoj al la unua argumento. Ĝi estas difinita jene:

function rmap () {
  for i (${argv[2,-1]}) { ${(ps: :)${i}} $1 }
}

Ĝi oni povas uzi, ekzemple, por diskuzadon kontroli, dosierinformon vidi, kaj la malfermajn dosiernumerojn de dosiero aŭ dosierujo vidi:

% rmap iudosierujo 'du -h' stat 'sudo lsof'

fp

Rapidan manieron por la realan kaj absolutan dosierindikon de dosiero aŭ dosierujo precizigi mi volas havi. Min ĉi tio helpas multe en skriptado. Ĝi estas difinita jene:

function fp () {
  echo "${1:A}"
}

Se mi estas en simbolligita dosierujo, kaj la realdosierindikon de . mi volas precizigi, la jenan mi povas ruli:

% fp .

Ĉi tiu funkcio estos grava en la sekva sekcio.

d

Ofte, kiam mi iras al dosierujo, serion de komandoj mi bezonas ruli. Tempon por maŝinskribado mi volas savi, do anstataŭ du komandojn ruli, nur unu mi nur devas ruli. Manieron por dosierujon rapide ŝanĝigi tra la dosierujstakoj per pushd mi volas havi. Ĝi estas difinita jene:

function d () {
  if (( ! $#@ )); then
      builtin cd
  elif [[ -d $argv[1] ]]; then
      builtin cd "$(fp $argv[1])"
      $argv[2,-1]
  elif [[ "$1" = -<-> ]]; then
      builtin cd $1 > /dev/null 2>&1
      $argv[2,-1]
  else
    echo "$0: no such file or directory: $1"
  fi
}

Kiam je d mi rulas sole:

% d

Mi iros al la hejmdosierujo, samkiel kion memstara cd devus fari:

Kiam je d mi rulas kun dosierujo kaj komando:

% d ~/Downloads ls -l

La aktuala dosierujo ŝanĝiĝos al ~/Downloads, tiam je ls -l mi rulas por la enhavon de tiu dosierujo montri.

Se la eligo de dirs -v estas la jena:

0       /usr/local
1       /tmp

Tiam, je d mi rulu, kaj la dua enskribo estas uzota kun komando:

% d -1 date

La dosierujo ŝanĝiĝos al /tmp/, tiam la komando date kuros.

d!

Kiel la nomo implicas, d! similas al sia kuzo nur, ke se la cela dosierujo ne ekzistas, ĝin ĝi kreas, kaj la saman konduton de d ĝi faras poste. Ĝi estas difinita jene:

function d! () {
  mkdir -p $argv[1]
  d "$@"
}

Ekzemple, je d! mi povas uzi por dosierujon scenigi antaŭ ISO-dosieron elŝuti:

% d! ~/Downloads/iso https://www.hundo.kato/muso/ve/ve.iso

rm!

Kiam mi certas, ke dosieron aŭ dosierujon mi volas forviŝi, mi ne volos ĝenita per invitoj, dum samtempe escepton por la hejmdosieron ne akcidente forviŝi mi volas havi. Ĝi estas difinita jene:

function rm! () {
  if [[ "$1" == "$HOME" || "$1" == "$HOME/" || "$1" == "~" || "$1" == "~/" ]]; then
      return 1
  else
    command rm -rf $@
  fi
}

La komando commando certigas, ke la sistemduumdosieron rm mi alvokas anstataŭ ia ŝela alinomo aŭ funkcio.

rm+

Kiam ajn mi volas rapide forviŝi arbon kiu havas multe da dosiero kaj dosierujo, la komandon parallel mi uzas por la forviŝadon ruli paralele, anstataŭ serie. Ĝi estas difinita jene:

function rm+ () {
  parallel 'rm -rf {}' ::: $@
}

La pakadministrilon de la sistemo kontrolu kiel je parallel instali.

rm@

Kelkfoje, dosieron aŭ dosierujon mi bezonas forviŝi sen la ŝancoj de retrovado. Por tion fari, la komandon shred mi uzas. Ĝi estas difinita jene:

function rm@ () {
  if [[ -d $1 ]]; then
      find $1 -type f -exec shred -vfzun 10 {} \;
      command rm -rf $1
  else
    shred -vfzun 10 $1
  fi
}

La pakadministrilon de la sistemo kontrolu kiel je shred instali.

def_mk

Helpilojn ci tiu helpilo generas. Onin ĝi permesas por funkciojn krei kiuj antaŭproduktajn dosierojn kreas antaŭ la vera komando estas rulita. Ĝi estas difinita kiel:

function def_mk () {
  eval "function ${argv[1]} () {
            if [[ \$# -ge 2 ]]; then
                if [[ ! -e \${@: -1} ]]; then
                     mkdir -p \${@: -1}
                fi

                command ${argv[2,-1]} \$@
            fi
        }"
}

Por ĝin uzi, la nomon de la funkcio kiu estos uzita kiel komando donu, kaj la malvolvo mem. Ĉi tiuj alvokoj estas ideale difinita en la agorddosiero.

cp!

Por je def_mk uzi kun cp ĝin alvoku jene:

def_mk cp! cp -rf

kiu malvolvas al:

function cp! () {
  if [[ $# -ge 2 ]]; then
    if [[ ! -e ${@: -1} ]]; then
      mkdir -p ${@: -1}
    fi
    command cp -rf $@
  fi
}

Onin la komando cp! permasas por dosierojn kaj dosierujojn kopii, la celan dosierujon kreante kiel necese:

%  tree
.
├── bar.txt
└── foo.txt

0 directories, 2 files

%  cp! * a

%  tree
.
├── a
│   ├── bar.txt
│   └── foo.txt
├── bar.txt
└── foo.txt

1 directory, 4 files

mv!

Por je def_mk uzi kun mv ĝin alvoku jene:

def_mk mv! mv -f

kiu malvolvas al:

function mv! () {
  if [[ $# -ge 2 ]]; then
    if [[ ! -e ${@: -1} ]]; then
      mkdir -p ${@: -1}
    fi
    command mv -f $@
  fi
}

Onin la komando mv! permasas por dosierojn movi al dosierujo, la celan dosirujon kreante kiel necese:

%  tree
.
├── bar.txt
└── foo.txt

0 directories, 2 files

%  mv! * b

%  tree
.
└── b
    ├── bar.txt
    └── foo.txt

1 directory, 2 files

Klavkombinoj

Ekster la komandoj kiuj estas maŝinskribitaj, klavkombinoj oni ankaŭ povas alvoki por ajnajn komandojn fari. Jen kelkaj, kiujn mi uzas ofte:

insert-last-word

Kiam la lastan vorton de la lasta komando mi volas enmeti, je insert-last-word mi vokas. Ekzemple, se la jenan oni havas, en kiu la ĉapelo estas la kursoro:

% dig hundo12345.kato.muzo.io
% mtr
      ^

Kiam je M-x insert-last-word EN mi rulas, la lastan vorton de la lasta komando ĝi enmetas, ĝin fari al:

% dig hundo12345.kato.muzo.io
% mtr hundo12345.kato.muzo.io
                             ^

Ĉi tio certigas, ke la argumento estas ĝuste kopiita.

La klavo estas defaŭlte bindita al M-.. Se oni volas certigi, ke tiun klavkombinon oni havas, la jenan metu en la agordo:

bindkey "\e." insert-last-word

copy-prev-shell-word

Se la lastan vorton en la aktuala komandlinio mi volas ripeti, je copy-prev-shell-word mi alvokas. Ekzemple, se la jenan oni havas:

% cp cxi.tio.estas.tre.longa.nomo
                                  ^

Kiam je M-x copy-prev-shell-word EN mi rulas, la lastan vorton ziŝo enmetas, gin fari al:

% cp cxi.tio.estas.tre.longa.nomo cxi.tio.estas.tre.longa.nomo
                                                              ^

Ĝin mi bindis al M-=. Por ĝin bindi al la agorddosiero:

bindkey "\e=" copy-prev-shell-word

Anstataŭigoj

Krome la rulo de M-x komandoj, onin ziŝo permesas por klavkombinojn difini kiu ajnan tekston enmeti ĉe la komandlinion, inkluzive stirsignoj.

La eligon de komandoj mi ofte bezonis akiri. Kutime la jenan mi faras:

% foo `some command`

% foo $(some command)

La antaŭa pli facilas por maŝinskribi, tamen ĝi ne povas nestiĝi; la ĉi tiu estas tro malfacila por maŝinskribi. Por tio, la klavkombinon M-` mi bindis jene:

% bindkey -s '\e`' '$()\C-b'

Do, se la jenan mi havas:

% foo
      ^

Kiam je M-` mi premas, la jenan mi akiros:

% foo $()
        ^

Citiloj

La bezonon por la argumenton de komandon citi mi ofte havas, precipe se metaesprimojn ĝi havas. Ofta kazo estas de jutubaj retadresoj, kiu la ? signon havas:

Por tio, je M-' bindis kiel jene:

% bindkey -s "\e'" "''\C-b"

Do, kiam la jenan mi havas:

% youtube-dl
             ^

Kiam je M-' mi premas, la jenan mi akiros:

% youtube-dl ''
              ^

Anstataŭ tri klavojn premi per mia klavaro, nur du mi nur devas premi, kaj ĝi certigas, ke paron de citiloj mi akiras.

Ĉion rikolti

Jen ĉiom da difinoj, kun kelkaj aldonaj helpiloj, en unu loko:

function map () {
  for i (${argv[2,-1]}) { ${(ps: :)${1}} $i }
}

function rmap () {
  for i (${argv[2,-1]}) { ${(ps: :)${i}} $1 }
}

function fp () {
  echo "${1:A}"
}

function d () {
  if (( ! $#@ )); then
      builtin cd
  elif [[ -d $argv[1] ]]; then
      builtin cd "$(fp $argv[1])"
      $argv[2,-1]
  elif [[ "$1" = -<-> ]]; then
      builtin cd $1 > /dev/null 2>&1
      $argv[2,-1]
  else
    echo "$0: no such file or directory: $1"
  fi
}

function d! () {
  mkdir -p $argv[1]
  d "$@"
}

function rm! () {
  if [[ "$1" == "$HOME" || "$1" == "$HOME/" || "$1" == "~" || "$1" == "~/" ]]; then
      return 1
  else
    command rm -rf $@
  fi
}

function rm+ () {
  parallel 'rm -rf {}' ::: $@
}

function rm@ () {
  if [[ -d $1 ]]; then
      find $1 -type f -exec shred -vfzun 10 {} \;
      command rm -rf $1
  else
    shred -vfzun 10 $1
  fi
}

function def_mk () {
  eval "function ${argv[1]} () {
            if [[ \$# -ge 2 ]]; then
                if [[ ! -e \${@: -1} ]]; then
                     mkdir -p \${@: -1}
                fi

                command ${argv[2,-1]} \$@
            fi
        }"
}

def_mk cp! cp -rf
def_mk mv! mv -f

function def_key () {
  while [[ $# -ge 2 ]]; do
    bindkey "$1" "$2"
    shift 2
  done
}

function def_keys () {
  def_key $keys
  unset keys
}

function def_out_key () {
  while [[ $# -ge 2 ]]; do
    bindkey -s "$1" "$2"
    shift 2
  done
}

function def_out_keys () {
  def_out_key $out_keys
  unset out_keys
}

keys=(
  "\e." insert-last-word
  "\e=" copy-prev-shell-word
); def_keys

out_keys=(
  '\e`' '$()\C-b'
  "\e'" "''\C-b"
); def_out_keys

Finrimarkoj

La komandlinion uzante, precipe per ŝelo tiom potenca kiel ziŝo, estas devige por esti konscie, kiun la ŝelon povas fari. Ne blinde uzu pakojn kiujn la ŝelon personecigas, sen kompreni kiujn ili faras.

Bonan ziŝigadon!