Linux, Proxy, Servidor de E-mail  Comentários desativados em Dkim-filter.conf
ago 232012


       dkim-filter.conf - Configuration file for dkim-filter




       dkim-filter(8)  implements  the  DKIM  specification  for  signing  and
       verifying e-mail messages on a per-domain  basis.   This  file  is  its
       configuration file, read on startup only.

       Blank  lines  are ignored.  Lines containing a hash ("#") character are
       truncated at the hash character to allow for comments in the file.

       Other content should be the name of  a  parameter,  followed  by  white
       space,  followed  by  the  value  of that parameter, each on a separate

       For parameters which are Boolean in nature, only the first byte of  the
       value  is  processed.  For positive values, the following are accepted:
       "T", "t", "Y", "y",  "1".   For  negative  values,  the  following  are
       accepted: "F", "f", "N", "n", "0".

       Many,  but  not  all, of these parameters are also available as command
       line options to dkim-filter(8).  However, new parameters are  generally
       not  added  as  command  line options so the complete set of options is
       available here, and thus use of the configuration file  is  encouraged.
       In  some  future  release, the set of available command line options is
       likely to get trimmed.

       See the dkim-filter(8) man page for details  about  how  and  when  the
       configuration file contents are reloaded.


       AllowSHA1Only (Boolean)
              Permit verify mode when only SHA1 support is available.  RFC4871
              requires that verifiers implement both SHA1 and SHA256  support.
              Setting  this feature changes the absence of SHA256 support from
              an error to a warning.

       AlwaysAddARHeader (Boolean)
              Add  an  "Authentication-Results:"  header  even   to   unsigned
              messages  from domains with no "signs all" policy.  The reported
              DKIM result will be "none" in  such  cases.   Normally  unsigned
              mail  from  non-strict domains does not cause the results header
              to be added.

       AlwaysSignHeaders (string)
              Specifies a list of headers which  should  be  included  in  all
              signature  header  lists  (the  "h="  tag) even if they were not
              present at the time the signature  was  generated.   The  string
              should  be  a comma-separated list of header names.  The list is
              empty by default.  The purpose of listing an absent header is to
              prevent  its addition between the signer and the verifier, since
              the verifier would include that header if  it  were  added  when
              performing verification, which would mean the signed message and
              the verified message were different and the  verification  would

       AutoRestart (Boolean)
              Automatically  re-start  on  failures.  Use with caution; if the
              filter fails instantly after it starts, this can cause  a  tight
              fork(2) loop.

       AutoRestartCount (integer)
              Sets  the maximum automatic restart count.  After this number of
              automatic restarts, the filter will give up  and  terminate.   A
              value of 0 implies no limit; this is the default.

       AutoRestartRate (string)
              Sets  the  maximum automatic restart rate.  If the filter begins
              restarting faster than the rate defined here, it  will  give  up
              and  terminate.   This is a string of the form n/t[u] where n is
              an integer limiting the count of restarts in the given  interval
              and  t[u]  defines  the  time interval through which the rate is
              calculated; t is  an  integer  and  u  defines  the  units  thus
              represented ("s" or "S" for seconds, the default; "m" or "M" for
              minutes; "h" or "H" for  hours;  "d"  or  "D"  for  days).   For
              example,  a  value  of  "10/1h" limits the restarts to 10 in one
              hour.  There is no default, meaning restart rate is not limited.

       Background (Boolean)
              Normally  dkim-filter  forks  and exits immediately, leaving the
              service running in the background.  This  flag  suppresses  that
              behaviour so that it runs in the foreground.

       BodyLengths (Boolean)
              Requests  that dkim-filter include the "l=" body length tag when
              generating signatures.  This indicates to the verifier that only
              a  certain  amount  of the original message was signed, allowing
              tolerance of things like  mailing  list  managers  which  append
              list-specific   text  to  the  end  of  mailings  it  processes.
              However, this also  enables  an  abuse  attack.   See  the  DKIM
              specification for more information.

       Canonicalization (string)
              Selects  the  canonicalization method(s) to be used when signing
              messages.  When verifying, the message’s DKIM-Signature:  header
              specifies  the  canonicalization  method.  The recognized values
              are relaxed and simple as defined  by  the  DKIM  specification.
              The  default  is  simple.   The  value may include two different
              canonicalizations separated by a slash ("/") character, in which
              case  the first will be applied to the headers and the second to
              the body.

       ClockDrift (integer)
              Sets the tolerance in seconds to  be  applied  when  determining
              whether  a  signature  was  either  expired  or generated in the
              future.  The default is 300.

       Diagnostics (Boolean)
              Requests the inclusion of "z=" tags in signatures, which  encode
              the  original  header  set  for use by verifiers when diagnosing
              verification failures.  Not recommended for normal operation.

       DNSTimeout (integer)
              Sets the DNS timeout  in  seconds.   A  value  of  0  causes  an
              infinite  wait.   The  default  is  5.  Ignored if not using the
              asynchronous resolver  package.   See  also  the  NOTES  section

       Domain (string)
              A comma-separated list of domains whose mail should be signed by
              this filter.  Mail from other domains will  be  verified  rather
              than being signed.

              The  value  of  this parameter may also be a filename from which
              domain names will be read.  The "#" character in such a file  is
              assumed  to  indicate  a comment.  An absolute path must be used
              (i.e. the first character must be a "/").

              In either case, the  domain  name(s)  may  contain  the  special
              character  "*" which is treated as a wildcard character matching
              zero or more characters in a domain name.

       ExternalIgnoreList (string)
              Identifies a file  of  "external"  hosts  which  may  send  mail
              through  the  server  as  one  of  the  signing  domains without
              credentials as such.  Basically suppresses  the  "external  host
              (hostname)  tried  to  send  mail  as  (domain)"  log  messages.
              Entries in the file should be of the same form as those  of  the
              PeerList option below.  The list is empty by default.

       FixCRLF (Boolean)
              Requests that the DKIM library convert bare CRs and LFs to CRLFs
              during body canonicalization, anticipating that an MTA somewhere
              before  delivery will do that conversion anyway.  The default is
              to leave them as-is.

       Include (string)
              Names  a  file  to  be  opened  and  read   as   an   additional
              configuration  file.   Nesting  is  allowed to a maximum of five

       InternalHosts (string)
              Identifies a file of internal hosts whose mail should be  signed
              rather than verified.  Entries in this file follow the same form
              as those of the PeerList option below.  If  not  specified,  the
              default of "" is applied.  Naturally, providing a value
              here overrides the default, so if mail from should  be
              signed,  the  list  provided  here  should  include that address

       KeyFile (string)
              Gives the location of a PEM-formatted private key to be used for
              signing all messages.  Ignored if KeyList is defined.

       KeyList (string)
              Gives  the  location  of  a  file listing rules for signing with
              multiple keys.  If present, overrides any KeyFile setting in the
              conifguration file.  The file named here should contain a set of
              lines of the  form  sender-pattern:signing-domain:keypath  where
              sender-pattern  is  a  pattern  to match against message senders
              (with the special character "*" interpreted  as  "zero  or  more
              characters"),  signing-domain  is  the domain to announce as the
              signing domain when generating signatures, and  keypath  is  the
              path  to  the  PEM-formatted  private key to be used for signing
              messages which match the sender-pattern.  The selector  used  in
              the  signature  will be the filename portion of keypath.  If the
              file referenced by keypath cannot be opened, the filter will try
              again  by appending ".pem" and then ".private" before giving up.

       LogWhy (boolean)
              If logging is enabled (see Syslog below), issues  very  detailed
              logging  about  the logic behind the filter’s decision to either
              sign a message or verify it.  The logic behind the  decision  is
              non-trivial  and can be confusing to administrators not familiar
              with its operation.  A description of how the decision  is  made
              can be found in the OPERATIONS section of the dkim-filter(8) man
              page.  This causes a large increase in the amount  of  log  data
              generated for each message, so it should be limited to debugging
              use and not enabled for general operation.

       MacroList (string)
              Defines a set of MTA-provided macros which should be checked  to
              see  if  the  sender  has been determined to be a local user and
              therefore whether or not the message should  be  signed.   If  a
              value  is  specified,  the value of the macro must match a value
              specified (matching is case-sensitive), otherwise the macro must
              be  defined  but  may  contain  any  value.  The set is empty by
              default.    The   general    format    of    the    string    is
              test1[,test2[,...]]    where   a   "test"   is   of   the   form
              macro[=value1[|value2[|...]]]; if one or more value  is  defined
              then  the  macro  must  be  set  to  one  of  the listed values,
              otherwise the macro must be set but can contain any value.

       MaximumHeaders (integer)
              Defines the maximum number  of  bytes  the  header  block  of  a
              message  may  consume before the filter will reject the message.
              This mitigates a denial-of-service  attack  in  which  a  client
              connects  to  the  MTA and begins feeding an unbounded number of
              header fields of arbitrary size; since the filter keeps a  cache
              of  these,  the  attacker  could cause the filter to allocate an
              unspecified amount of memory.  The default is 65536; a value  of
              0 removes the limit.

       MaximumSignedBytes (integer)
              Specifies  the  maximum  number  of  bytes of message body to be
              signed.  Messages shorter than this  limit  will  be  signed  in
              their  entirety.   Setting  this  value forces BodyLengths to be

       MilterDebug (integer)
              Sets the debug level to be requested from  the  milter  library.
              The default is 0.

       Minimum (string)
              Instructs  the  verification  code  to fail messages for which a
              partial  signature  was  received.   There  are  three  possible
              formats:  min  indicating at least min bytes of the message must
              be signed (or if the message is smaller than min then all of  it
              must be signed); min% requiring that at least min percent of the
              received message must be signed; and min+ meaning there  may  be
              no  more than min bytes of unsigned data appended to the message
              for it to be considered valid.

       Mode (string)
              Selects operating modes.   The  string  is  a  concatenation  of
              characters   which  indicate  which  mode(s)  of  operation  are
              desired.  Valid modes are s  (signer)  and  v  (verifier).   The
              default  is  sv  except in test mode (see the dkim-filter(8) man
              page) in which case the default is v.

       MTA (string)
              A comma-separated list  of  MTA  names  (a  la  the  sendmail(8)
              DaemonPortOptions Name parameter) whose mail should be signed by
              this filter.  There is no default.

       OmitHeaders (string)
              Specifies a  list  of  headers  which  should  be  omitted  when
              generating  signatures.   The string should be a comma-separated
              list of header names.  If an entry in the list names any  header
              which  is  mandated  by  the  DKIM  specification,  the entry is
              ignored.  A set of headers is listed in the  DKIM  specification
              as  "SHOULD  NOT" be signed; the default list for this parameter
              contains  those  headers   (Return-Path,   Received,   Comments,
              Keywords,  Bcc,  Resent-Bcc  and  DKIM-Signature).   To  omit no
              headers, simply use the string "-" (or  any  string  which  will
              match  no  headers).   Note  that  specifying  a  list with this
              parameter replaces the default entirely.

       On-BadSignature (string)
              Selects the action  to  be  taken  when  a  signature  fails  to
              validate.    Possible   values   (with   abbreviated   forms  in
              parentheses): accept (a) accept the message; discard (d) discard
              the  message;  tempfail  (t)  temp-fail  the message; reject (r)
              reject the message.  The default is accept.

       On-Default (string)
              Selects the action to be taken when any verification or internal
              error  of any kind is encountered.  This is processed before the
              other "On-" values so it  can  be  used  as  a  blanket  setting
              followed by specific overrides.

       On-DNSError (string)
              Selects  the  action  to  be taken when a transient DNS error is
              encountered.  Possible values are the  same  as  those  for  On-
              BadSignature.  The default is tempfail.

       On-InternalError (string)
              Selects  the  action  to be taken when an internal error of some
              kind is encountered.  Possible values are the same as those  for
              On-BadSignature.  The default is tempfail.

       On-NoSignature (string)
              Selects  the action to be taken when a message arrives unsigned.
              Possible values are the same as those for On-BadSignature.   The
              default is accept.

       On-Security (string)
              Selects the action to be taken when a message arrives containing
              properties that may be a security concern.  Possible values  are
              the same as those for On-BadSignature.  The default is tempfail.

       On-SignatureMissing (string)
              Selects the action to be taken when a message  arrives  unsigned
              from  a  domain  which advertises a "we sign everything" policy.
              Possible values are the same as those for On-BadSignature.   The
              default is accept.

       PeerList (string)
              Identifies  a  file  of  "peers"  which identifies clients whose
              connections  should  be  accepted  without  processing  by  this
              filter.  The file should contain on each line a hostname, domain
              name  (e.g.  ""),  IP  address,  an   IPv6   address
              (including   an   IPv4  mapped  address),  or  a  CIDR-style  IP
              specification (e.g. "").  An entry beginning  with
              a  bang  ("!")  character  means  "not",  allowing exclusions of
              specific hosts that are otherwise members of larger  sets.   The
              order of entries in this file is therefore significant.

       PidFile (string)
              Specifies  the path to a file which should be created at process
              start containing the process ID.

       POPDBFile (string)
              Requests that the filter consult a POP  authentication  database
              named  in the string for IP addresses that should be allowed for
              signing.  The filter must be compiled with the POPAUTH  flag  to
              enable this feature, since it adds a library dependency.

       Quarantine (Boolean)
              Requests that messages which fail verification be quarantined by
              the MTA.  (Requires a sufficiently recent version of the  milter

       QueryCache (Boolean)
              Instructs  the  DKIM  library to maintain its own local cache of
              keys and policies retrieved from DNS, rather than relying on the
              nameserver  for caching service.  Useful if the nameserver being
              used by the filter is not local.  The filter  must  be  compiled
              with  the QUERY_CACHE flag to enable this feature, since it adds
              a library dependency.

       RemoveARAll (Boolean)
              Removes all Authentication-Results:  header  fields  which  also
              satisfy  the  requirements  of  RemoveARFrom below.  By default,
              only those containing a DKIM result are removed.

       RemoveARFrom (string)
              Lists patterns of hostnames whose Authentication-Results: header
              fields  should  be  removed  before  the  message  is passed for
              delivery.  By default only  those  headers  matching  the  local
              host’s canonical name will be removed.  If more than one pattern
              is desired, the list should  be  comma-separated.   Matching  is
              only  done  on  full  hostnames  (e.g. "") or on
              domain names (e.g. "").

       RemoveOldSignatures (Boolean)
              Removes all existing signatures when operating in signing  mode.

       SignHeaders (string)
              Specifies  the  list  of  headers  which should be included when
              generating signatures.  The string should be  a  comma-separated
              list  of  header  names.   If the list omits any header which is
              mandated by the DKIM specification, those headers are implicitly
              added.    By   default,   those   headers  listed  in  the  DKIM
              specification as "SHOULD"  be  signed  will  be  signed  by  the
              filter.   Specifying  a  list  here replaces that list entirely.
              See the OmitHeaders configuration option for more information.

       Selector (string)
              Defines the name  of  the  selector  to  be  used  when  signing
              messages.   See  the  DKIM specification for details.  Used only
              when signing with a single key; see the KeyList parameter  above
              for more information.

       SendReports (Boolean)
              If  true,  when  a  signature verification fails and the signing
              site advertises a reporting address (i.e.   r=user@host  in  its
              policy record), the filter will send a structured report to that
              address containing details needed to reproduce the problem.

       SignatureAlgorithm (string)
              Selects the signing algorithm to use when generating signatures.
              If  the  filter  was  compiled against version 0.9.8 or later of
              OpenSSL then both rsa-sha1 and rsa-sha256 are available and  the
              latter  is the default.  Otherwise, only the former is available
              and it is (obviously) the default.

       SignatureTTL (integer)
              Sets the time-to-live, in seconds, of  signatures  generated  by
              the  filter.   If  not  set,  no  expiration  time  is  added to

       Socket (string)
              Specifies the socket that should be established by the filter to
              receive   connections  from  sendmail(8)  in  order  to  provide
              service.  socketspec is in one of two  forms:  local:path  which
              creates   a  UNIX  domain  socket  at  the  specified  path,  or
              inet:port[@host] which creates a TCP  socket  on  the  specified
              port.   If  the  host is not given as either a hostname or an IP
              address, the socket will be listening on all  interfaces.   This
              option  is  mandatory either in the configuration file or on the
              command line.

       StrictTestMode (Boolean)
              Selects strict CRLF mode during testing (see the -t command line
              flag  in  the  dkim-filter(8)  man page); messages for which all
              header  fields  and  body  lines  are  not  CRLF-terminated  are
              considered malformed and will produce an error.

       SubDomains (Boolean)
              Sign  subdomains of those listed by the Domain parameter as well
              as the actual domains.

       Syslog (Boolean)
              Log via calls to syslog(3) any interesting activity.

       SyslogFacility (string)
              Log via calls  to  syslog(3)  using  the  named  facility.   The
              facility   names   are   the   same   as  the  ones  allowed  in
              syslog.conf(5). The default is mail .

       SyslogSuccess (Boolean)
              Log  via  calls  to  syslog(3)  additional  entries   indicating
              successful signing or verification of messages.

       TestPublicKeys (string)
              Names  a  file  from which public keys should be read.  Intended
              for use only during automated testing.

       UMask (integer)
              Requests a  specific  permissions  mask  to  be  used  for  file
              creation.   This  only  really applies to creation of the socket
              when Socket specifies a UNIX domain socket, and to  the  PidFile
              (if any); temporary files are created by the mkstemp(3) function
              which enforces a specific file mode on  creation  regardless  of
              the process umask.  See umask(2) for more information.

       UserID (string)
              Attempts   to   become  the  specified  userid  before  starting
              operations.  The value  is  of  the  form  userid[:group].   The
              process  will be assigned all of the groups and primary group ID
              of the named userid unless an alternate group is specified.

       UseASPDiscard (Boolean)
              If "true", requests discard of messages which are determined  to
              be suspicious according to the author domain’s published signing
              procedure (ASP) record if that record also recommends discard of
              such messages.

       X-Header (Boolean)
              Causes  dkim-filter  to  add a header indicating the presence of
              this filter in  the  path  of  the  message  from  injection  to
              delivery.   The  product’s  name,  version,  and  the job ID are
              included in the header’s contents.


       When using DNS timeouts (see the DNSTimeout option above), be sure  not
       to  use  a  timeout  that  is  larger  than  the timeout being used for
       interaction between sendmail and the filter.  Otherwise, the MTA  could
       abort  a  message  while  waiting for a reply from the filter, which in
       turn is still waiting for a DNS reply.


       This man page covers version 2.5.4 of dkim-filter.


       Copyright (c) 2007, 2008, Sendmail, Inc. and its suppliers.  All rights


       dkim-filter(8), sendmail(8)

       RFC4871 - DomainKeys Identified Mail

       Authentication-Results Internet Draft

Como criar pacotes .MSI

 Windows  Comentários desativados em Como criar pacotes .MSI
ago 232012

Hoje vou explicar como proceder na necessidade de criar pacotes .MSI para automatizar a instalação de um aplicativo ou na maioria dos casos ser aplicado às GPOs.

O que é um arquivo .MSI ?
Em um modo bruto de explicação é um pacote que contém todas as informações/configurações necessárias para que não necessite da intervenção de um usuário para algumas ações a serem tomadas como por exemplo (Acordar com o termo de licença, definir pasta de instalação, entre outras …).

Os pacotes .msi são comumente utilizados em GPOs para instalar uma respectiva aplicação em um determinado conjunto de computadores de um domínio.

Nesse artigo explicarei de uma forma detalhada como criar o pacote .MSI utilizando o software AppDeploy Repackager que pode ser baixado clicando sobre ele. Há várias recomendações na internet sobre a utilização do Veritas Discover, porém por experiência própria já tive diversos problemas com a feramenta.

Recomendação para criar o .MSI
  • Uma máquina limpa (considere como limpa uma máquina somente com windows e service pack atual, que chegue mais próximo do ambiente atual do que dispõe em sua rede, pode ser usado máquinas virtuais para criação)
  • O software AppDeploy Repackager instalado na máquina que irá criar os pacotes.


1- A instalação do AppDeploy Repackager  é muito simples na qual não vejo nem necessidade de detalhar, é um seguido de “Next, Next, Finish”

2- Será criado um atalho na área de trabalho do aplicativo, ao iniciá-lo será apresentada uma tela de boas vindas, clicando em Next iniciamos o processo de criação.

3- Na tela seguinte “Capture Basic Information” devemos proceder da seguinte forma, em seguida clicar em Next:

  • Setup File Location – Indicar onde o arquivo .exe que será convertido está localizado
  • Application Name – O nome em que o pacote será definido após o término do processo
  • Version – Série do aplicativo, geralmente uso números para diferenciar uma versão para a outra.
  • Company Name – Pode ser o nome da empresa que desenvolve o software ou o da sua empresa, como achar melhor.

4-  Em “Pre Installation Snapshot” você pode definir uma unidade e chave de registros específicos para se fazer o scan e 1º Snapshot, por padrão não marco nada e vou para a tela seguinte que inicia em efetivo o snapshot.

5- Após a execução do snapshot será necessário instalar o programa (a ser criado o pacote) na máquina.
ATENÇÃO: Todas as ações tomadas nesse processo serão as coletadas pelo snapshot seguinte.

6- Faça as configurações no software se necessário (no caso do nosso exemplo em que estou gerando a do 7zip, estou ativando as extensões que ele poderá ler.

7- Após esse processo será apresentada a tela “Post Installation Snapshot”, no qual não marco na por padrão (igual ao explicado no ítem 4 acima), em seguida será feita comparação entre os 2 snapshots.

8- Em “Package Content Review” será apresentada a diferença entre os 2 snapshots, marque sempre todas as opções de Included Files Items e em seguida Included Registery Items.

9- Em “Create Recipe File and MSI” você poderá definir alguns atalhos para o pacote a ser criado, no nosso exemplo na janela suspensa eu selecionei o executável 7zFM.exe e cliquei em Select.

10- Defini o nome do atalho a ser criado como: Atalho 7Zip, defini que ele será criado somente no Desktop, e escolhi o ícone a ser usado por ele (lembrando que eu posso usar qualquer ícone porém devo selecionar o mesmo usando a caixa Icon/Exe File. Posso fazer esse procedimento para todos os aplicativos, veja o que atende a sua necessidade.

11- Voltaremos para mesma tela anterior, na qual definiremos:

  • Target Path – Caminho em que o .MSI será salvo
  • Recipe File Name – É um arquivo .xml no qual contém todas as instruções criadas anteriormente
  • MSI Name – Nome do arquivo a ser criado

12- Após clicarmos em Next devemos aguardar a criação do mesmo, no qual será salvo conforme definido no passo anterior.

13- Só a nível de teste, rode o arquivo gerado e veja se atende aos passos criados anteriormente, nosso caso atendeu, atenção para o ícone no desktop (definido no passo 10) e opções de extensão (definido no passo 6).


Com esse procedimento fica muito mais fácil gerar seus arquivos .MSI e distribuí-los através das GPOs.

Espero que tenham gostado


Monitoramento com Zabbix 2.0

 Linux, Redes  Comentários desativados em Monitoramento com Zabbix 2.0
ago 212012

Instalando as dependências e o Zabbix

Pessoal, neste tutorial, vou explicar como instalar e configurar o Zabbix 2.0, um monitor de rede que coleta e guarda informações da rede e de hosts remotos, sendo possível realizar consultas de performance e estado, posteriormente.

Neste exemplo, utilizei uma máquina virtual com Debian Squeeze com 1 GB de RAM e processador Dual-Core.

Antes de iniciarmos a instalação em si, precisamos atualizar nosso sistema e instalar as dependências para que o Zabbix funcione perfeitamente:

# aptitude update
# aptitude upgrade

# aptitude install make flex gcc gpp php-net-socket libpq5 libpq-dev snmp apache2 libapache2-mod-php5 php5 php5-gd php5-curl libcurl4-openssl-dev php5-mysql php5-snmp php-pear perl-base liburi-perl libapache2-mod-perl2 libwww-perl libtool libextutils-pkgconfig-perl pkg-config libsnmp-dev libcurl3 rcconf libgd-text-perl php5-cgi perl-modules libpdf-api2-perl libssh2-1-dev mysql-server libmysql++-dev libmysqlclient-dev snmpd libsnmp-dev curl libiksemel-dev libiksemel-utils fping lm-sensors libsysfs2

Obs.: Durante o processo de instalação do MySQL, será solicitada a senha de root, cuidado para não perder esta senha.

Crie o usuário Zabbix no sistema:

# adduser –disabled-password –disabled-login –shell=/bin/false zabbix

Agora, vamos baixar o pacote do Zabbix:

# cd /opt
# wget -cv

Descompacte o arquivo:

# tar -xvzf zabbix-2.0.0.tar.gz
# cd zabbix-2.0.0/

Vamos executar o ./configure com alguns parâmetros:

# ./configure –enable-server –enable-agent –with-mysql –with-net-snmp –with-libcurl –with-jabber
# make install

Com isso, nosso sistema já está instalado, mas ainda faltam alguns ajustes, vamos a eles.


Ajustando as configurações

Iremos criar a base de dados no MySQL e executar os scripts “.sql”, do Zabbix:

# mysql -u root –p

(Entre com sua senha de root)

Mysql> create database zabbix;
Mysql> grant all privileges on zabbix.* to zabbix@localhost identified by ‘nova_senha’;
Mysql> quit;

# cd /opt/zabbix-2.0.0/database/mysql/

# mysql -D zabbix -u zabbix -p < schema.sql

(Entre com sua senha do usuário zabbix)

# mysql -D zabbix -u zabbix -p < images.sql

(Entre com sua senha do usuário zabbix)

# mysql -D zabbix -u zabbix -p < data.sql

(Entre com sua senha do usuário zabbix)

Pronto. Com isso, nossa configuração do MySQL está encerrada, vamos para às confs do Zabbix:

# mkdir /etc/zabbix
# chown –R zabbix.zabbix /etc/zabbix
# cd /usr/local/etc/zabbix
# pico zabbix_agent.conf

Confirme se a linha define o IP do servidor Zabbix está apontando para ele mesmo:


# pico zabbix_server.conf

Altere as linhas a seguir no seu arquivo:


Obs.: No meu caso, coloquei a senha do usuário Zabbix do MySQL como zabbix.

Salve e saia do arquivo.

# cp zabbix_*.conf /etc/zabbix/

Agora, temos que copiar os scripts de inicialização do Zabbix para iniciar automaticamente no boot:

# cd /opt/zabbix-2.0.0/misc/init.d/debian/
# cp zabbix-* /etc/init.d/
# chmod 755 /etc/init.d/zabbix­server
# chmod 755 /etc/init.d/zabbix­agent
# rcconf

Marque os dois scrips do Zabbix e dê OK.

# /etc/init.d/zabbix­server start
# /etc/init.d/zabbix­agent start
# ps –aux | grep zabbix

Ajustando o frontend e concluindo a instalação

Se o Zabbix estiver rodando numa boa, podemos seguir com a instalação e partir para o frontend:

# cp -R /opt/zabbix-2.0.0/frontends/php/* /va/WWW/zabbix/
# pico /etc/php5/apache2/php.ini

Adicione as seguintes linhas, ao final do arquivo:

date.timezone = America/Sao_Paulo
max_execution_time = 300
memory_limit = 512M
post_max_size = 32M
upload_max_filesize = 16M
max_execution_time = 600
max_input_time = 600

Reinicie o Apache para atualizar as novas configurações do PHP:

# /etc/init.d/apache2 restart
# chown -R www-data:zabbix /home/viaza132/www/zabbix

Agora abra o navegador e digite: <endereco_do_servidor>/zabbix/

Será exibida a tele inicial de configuração do Zabbix.

Clique em Próximo:

Se estiver tudo OK, clique em “Próximo”, se não, reveja suas configurações no arquivo php.ini.

Aqui, iremos colocar o nome da base de dados do MySQL, o nome do usuário e a senha, clique em “Test connection”, se aparecer um Ok, clique em próximo:

Clique em “Próximo”:

Clique em “Próximo”:

Clique em “Finsh”:

Irá aparecer a seguinte tela no browser:

Com tudo que fizemos até aqui, o servidor Zabbix ainda não está sendo monitorado, para que isso aconteça, clique na aba:

Configuration -> hosts para visualizar

O host do Zabbix, depois clique em “Not monitored” e ative-o na janela que irá aparecer:

Para mudar o idioma para Português, vá no menu Profile, no canto superior direito da tela, e mude para Português no campo “Language”, depois é só salvar.

Bem pessoal, é isso.

Espero que este tutorial seja útil para vocês.

No próximo tutorial, iremos aprender como configurar um host para ser monitorado pelo Zabbix e como adicionamos ele aqui em nosso servidor.

Até mais. Qualquer dúvida, é só postar. vlw!

Artigo previamente publicado em:

Autenticação de servidores CentOS/Red Hat 6 em Windows 2008

 Clusterweb, Linux, Windows  Comentários desativados em Autenticação de servidores CentOS/Red Hat 6 em Windows 2008
ago 212012
Introdução – Pré-requisitos

Este artigo foi criado para ensinar a configuração de autenticação de servidores CentOS e Red Hat(versão 6) no Windows 2008.Diversos artigos encontrados na Internet, fazem uso do Winbind para possibilitar esta autenticação, contudo, como esta configuração depende da instalação do serviço Samba (e consequente abertura de portas, vulnerabilidades, etc), optei por fazer esta configuração utilizando-se apenas do serviço de LDAP, que já é disponibilizado pelo Windows 2008, e pelo serviço Kerberos 5.

Assim, não é necessária a abertura de nenhuma porta nos clientes de autenticação, e caso seja uma autenticação entre redes distintas com firewall, apenas a abertura das portas do LDAP, Kerberos 5 e DNS serão suficientes.


Estas definições serão utilizadas durante o artigo, e serão explicadas conforme o desenvolvimento do mesmo:

  • Hostname do Domain Controller: Homer (HOMER.SPRINGFIELD.CORP)
  • IP do Domain Controller:
  • Conta de serviço LDAP: CN=AuthLinux,CN=Users,DC=Springfield,DC=Corp
  • Usuário criado para testes de Logon: rkatz@SPRINGFIELD.CORP
  • Grupo criado com atributos Unix: Linux

Configuração do Windows 2008 (Domain Controller)

Assumindo que o seu Domain Controller já esteja instalado e em funcionamento, as seguintes configurações abaixo deverão ser feitas:

1. Atualização do ambiente

Não é necessariamente um pré-requisito para o correto funcionamento do ambiente, mas recomendo executar um ‘Windows Update’ no ambiente, apenas por garantia. 😉

2. Instalação do Unix Integration Tools

Para que a autenticação funcione com sucesso, devemos instalar o Unix Integration Tools nos Domain Controllers. Esta nova rolecria atributos específicos necessários para a autenticação em Unix/Linux, como Home Directory e Default Shell.

  • Em Server Manager, na aba (lateral esquerda), selecionar ‘Roles’.
  • Na seção ‘Role Services’ da role ‘Active Directory Domain Services’, adicionar o serviço ‘Identity Management for Unix’, através do link ‘Add Role Services’, incluindo todos os demais serviços (Server for Network Information Services, Password Syncronization e Administration Tools).

Criação das contas no DC

Para o correto funcionamento da configuração, devemos criar uma conta de serviço que será utilizada para o BIND (conexão) ao LDAP, uma vez que o Windows 2008 não permite conexão anônima ao LDAP. Também criaremos um grupo e uma conta exemplo, que serão utilizados nos testes de Login.

Conta de serviço

Esta conta deverá ser criada com a política de “não expiração de senha”, pois esta senha será utilizada na configuração de todos os clientes. Caso a senha expire, a mesma deverá ser trocada no servidor, e consequentemente em todos os clientes.

* Importante: Lembre-se ao criar esta conta, de que o ‘Full Name’ da conta criada é utilizada como RDN no LDAP.


  • FullName=Bart Simpson
  • CN=Bart Simpson
  • CN=Users
  • DC=Domínio.

Assim, recomenda-se criar a conta com um ‘Full Name’ de uma palavra, como ‘AuthLinux’, para não haver maiores problemas.

A conta será criada conforme abaixo:

  • FullName: AuthLinux
  • User Logon Name: AuthLinux
  • Senha (exemplo, alterar no seu ambiente): 12qw!@QW
  • Configurações: ‘User Cannot Change Password’, e ‘Password Never Expires’

Após a criação desta conta de serviço, alterar o seu grupo, colocando-o apenas como membro do grupo “Domain Guests” e removendo todos os demais grupos, de forma que este usuário não possua nenhuma permissão no domínio.

Criação do Grupo

Ou, alteração de grupo já existente.

Deve ser criado um grupo (ou alterado um já existente) para que o mesmo possua atributos Unix, possibilitando sua utilização em nosso ambiente. Isso deve ser feito, primeiro criando-se o grupo (caso já não exista) e depois, alterando-o conforme abaixo.

No nosso exemplo, foi criado o grupo “Linux”. Após isso, na aba ‘Unix Attributes’ das propriedades do grupo, alterar o NIS Domain para ‘SPRINGFIELD’ (ou o Domínio utilizado). Manter o GID criado padrão, e não adicionar nenhum usuário no grupo.

Criação de usuário com permissão de Login

Ou, alteração de usuário já existente.

Um usuário deve ser criado (ou alterado) de forma que possamos efetuar logon em um ambiente Unix. Nesse artigo, será criado o usuário ‘rkatz’, conforme abaixo:

  • Criar o usuário (ou alterar) desabilitando a opção ‘User Must Change Password on Next Logon’;
  • Editar o usuário, e na aba ‘Unix Attributes’ alterar o NIS Domain para ‘SPRINGFIELD’;
  • Alterar o ‘Login Shell’ para o Shell padrão utilizado no ambiente (como /bin/bash);
  • E, Primary group Name/GID para o grupo criado acima (Linux).
Configuração do S.O.

Assumindo que sua instalação do sistema operacional já esteja feita (eu utilizei o CentOS neste artigo), os seguintes passos devem ser feitos:

Atualização do sistema operacional

Tal como no ambiente Windows, esse não é um pré-requisito, mas altamente recomendável para garantirmos a estabilidade da autenticação.

Configuração de DNS e NTP

O nosso cliente deve ‘conhecer’ o domínio que será utilizado, para o seu correto funcionamento. Assim, no arquivo /etc/resolv.conf, o IP dos Domain Controllers do ambiente, deverão ser utilizados conforme abaixo:


Testar o funcionamento, efetuando um nslookup (ou ping, mesmo) para o nome SPRINGFIELD.CORP (Domínio) e HOMER.SPRINGFIELD.CORP (Domain Controller) e verificar o correto funcionamento.

Também, o horário do cliente deverá estar sincronizado com o do restante do domínio. Assim, os pacotes do NTP deverão ser instalados:

# yum install ntp ntpdate

Após a instalação dos pacotes de NTP, uma primeira sincronização deverá ser efetuada com o comando ntpdate:

# ntpdate springfield.corp

Feita a primeira sincronização do horário, o arquivo /etc/ntp.conf deve ser editado, removendo-se todas as linhas ‘server’ e adicionando apenas a seguinte:

server springfield.corp

Após isso, adicionar o serviço de NTP à inicialização do ambiente, e iniciar o serviço. Então, verificar o funcionamento:

# chkconfig ntpd on
# /etc/init.d/ntpd on
# ntpq -c pe

remote             refid        st t  when poll reach  delay   offset   jitter
==============================================================================   2  u   12   64   377    0.762  449.851  17.746

Instalação dos pacotes de autenticação e Kerberos

Em uma instalação padrão os pacotes necessários para autenticação não vem instalados por padrão. Assim, devemos instalar os pacotes necessários, conforme abaixo:

# yum install nss-pam-ldapd krb5-workstation pam_krb5 nscd openldap-clients

Verificação de conta de serviço

Para garantirmos o correto funcionamento, a conta de serviço criada na configuração do Windows 2008 (AuthLinux) deverá ser testada. Podemos testar essa conta com o seguinte comando (será solicitada a senha da conta):

# ldapsearch -v -x -H “ldap://springfield.corp” -D “cn=AuthLinux,cn=Users,dc=Springfield,dc=corp” -b “dc=Springfield,dc=corp” -s sub -W

Caso o comando não retorne nenhum erro (mas uma saída LDIF), a conta de serviço está funcionando corretamente. Caso contrário, deverá ser verificado se os dados utilizados para autenticação (cn, senha) estão corretos.

Autenticação LDAP

Após a configuração do ambiente, devemos configurar o sistema operacional de forma a autenticar-se no AD. As seguintes configurações devem ser efetuadas:

NSLCD (Autenticação LDAP)

O NSLCD (local LDAP name service daemon) será utilizado para a autenticação ao LDAP. Antes configurado através do arquivo /etc/ldap.conf (no RHEL 5 e derivados), agora este recurso possui um daemon próprio.

Para configurá-lo, devemos alterar o arquivo /etc/nslcd.conf conforme abaixo (as explicações estão nos comentários do arquivo):

# Versao LDAP
ldap_version 3
# Usuario e grupo para executar o daemon
uid nslcd
gid ldap# Limite de timeout de bind e de busca
bind_timelimit 30
timelimit 30

# Servidor LDAP e BaseDN
uri ldap://springfield.corp
base dc=springfield,dc=corp

# O SSL ainda não será configurado
ssl no
tls_cacertdir /etc/openldap/cacerts

# usuário e senha de serviço
binddn cn=AuthLinux,cn=Users,dc=springfield,dc=corp
bindpw 12qw!@QW

scope sub
scope   group   sub scope   hosts   sub

# Ignorar lookup de grupos para os usuários de sistema
nss_initgroups_ignoreusers root,nslcd,bin,daemon,mail,nobody,sshd,nscd,ntp

# Caso seja necessário algum filtro, para apenas algum usuário de algum grupo logar
# pam_authz_search (gidNumber=10000)

# Configuracoes de Mapping – AD
pagesize 1000
referrals off
filter passwd (&(objectClass=user)(!(objectClass=computer))(uidNumber=*)(unixHomeDirectory=*))
map    passwd uid            sAMAccountName
map    passwd homeDirectory  unixHomeDirectory
map    passwd gecos          displayName
filter shadow (&(objectClass=user)(!(objectClass=computer))(uidNumber=*)(unixHomeDirectory=*))
map    shadow uid            sAMAccountName
map    shadow shadowLastChange pwdLastSet
filter group (objectClass=group)
map    group uniqueMember    member

Após isso, devemos iniciar o daemon do nslcd e colocá-lo na inicialização:

# chkconfig nslcd on
# /etc/init.d/nslcd on

Kerberos 5

A configuração do Kerberos deverá ser feita de forma a validar um usuário, e permitir, entre outras coisas, sua autenticação e posteriores operações (como query de grupos a que pertence, etc).

A configuração deverá ser feita conforme abaixo.

Alterar o arquivo /etc/krb5.conf, conforme abaixo (as explicações estão nos comentários do arquivo):

# Nao validar o hostname do servidor (senao precisa de entradas no DNS e Reverso)
validate = false# Locais de Logging
default = FILE:/var/log/krb5libs.log
kdc = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmind.log

# Configuracoes Padrao
# Dominio Padrao – SPRINGFIELD.CORP – Deve ser o mesmo do AD
default_realm = SPRINGFIELD.CORP
dns_lookup_realm = false
dns_lookup_kdc = false
ticket_lifetime = 24h
renew_lifetime = 7d
forwardable = true

# Configuracao do servidor de KERBEROS
# Utilizando o nome do DOMINIO, ele vai para o DC
admin_server = SPRINGFIELD.CORP

# Configuracoes de DOMINIO – Qual REALM deve ser usado para qual dominio
springfield.corp = springfield.corp
.springfield.corp = springfield.corp

Testar a geração de um ticket de autenticação para um usuário qualquer do domínio, como o Administrador:

# kinit -V Administrator@SPRINGFIELD.CORP

A saída seria:

Using default cache: /tmp/krb5cc_0
Using principal: Administrator@SPRINGFIELD.CORP
Password for Administrator@SPRINGFIELD.CORP: [DIGITAR A SENHA]
Authenticated to Kerberos v5

Caso o retorno seja diferente de:

Authenticated to Kerberos v5

A configuração deve ser verificada novamente, pois alguma configuração foi efetuada incorretamente.

Configuração do NSCD e NSSWITCH

Devemos agora, configurar o daemon de cache de logins, e o NSSWITCH, que irá direcionar a autenticação de usuários e grupos para o NSLCD (LDAP), caso não seja encontrado um usuário local.

Por padrão, o arquivo /etc/nscd.conf já vem configurado com parâmetros aceitáveis, sendo necessário apenas descomentar a linha “logfile /var/log/nscd.log”, para que o daemon efetue log, caso algo dê errado.

Devemos então, alterar o arquivo /etc/nsswitch.conf, deixando as linhas: passwd, shadow e group, conforme abaixo:

  passwd:    files ldap
shadow:    files ldap
group:     files ldap

Por fim, o daemon do NSCD deve ser colocado na inicialização do S.O., e ser iniciado:

# chkconfig nscd on
# /etc/init.d/nscd start

Para verificar o funcionamento correto da configuração, utilizar o comando getent no usuário e grupo criado na etapa de “Pré requisitos”:

# getent passwd rkatz

A saída seria:

rkatz:*:10002:10000:Ricardo P. Katz:/home/rkatz:/bin/bash


# getent group Linux


Configuração do PAM

A etapa final da configuração é a alteração do PAM (Plugable Authentication Modules), de forma que as autenticações do Sistema Operacional sejam enviadas ao servidor LDAP (Domain Controller).

Adicionalmente, quando um usuário não possuir diretório ‘home’ no ambiente, o esperado é que o PAM crie esse diretório.

O arquivo /etc/pam.d/system-auth deverá ser alterado para ficar conforme abaixo. O arquivo aqui é um exemplo, sugiro que verifique se não há nenhum mecanismo de autenticação já em uso no ambiente, e adeque as configurações às suas necessidades:

auth        required
auth        sufficient
auth        sufficient nullok try_first_pass
auth        requisite uid >= 500 quiet
auth        sufficient use_first_pass
auth        required
account     required
account     sufficient
account     sufficient uid < 500 quiet
account     [default=bad success=ok user_unknown=ignore]
account     required
password    requisite try_first_pass retry=3 type=
password    sufficient sha512 shadow nullok try_first_pass use_authtok
password    sufficient use_authtok
password    required
session     optional revoke
session     required
session     required skel=/etc/skel umask=0022
session     [success=1 default=ignore] service in crond quiet use_uid
session     required
session     optional

Alterar também o arquivo /etc/pam.d/password-auth, conforme configuração abaixo:

auth        required
auth        sufficient nullok try_first_pass
auth        requisite uid >= 500 quiet
auth        sufficient use_first_pass
auth        required
account     required broken_shadow
account     sufficient
account     sufficient uid < 500 quiet
account     [default=bad success=ok user_unknown=ignore]
account     required
password    requisite try_first_pass retry=3 type=
password    sufficient sha512 shadow nullok try_first_pass use_authtok
password    sufficient use_authtok
password    required
session     optional revoke
session     required
session     [success=1 default=ignore] service in crond quiet use_uid
session     required
session     optional

Após as alterações, logar-se em um novo terminal com o usuário criado no AD (no exemplo, o usuário: rkatz), e verificar se o login é autorizado, bem como o diretório home criado.

Verificar também com o comando id, se os grupos a que o usuário pertence são carregados. Caso não funcione, os arquivos /var/log/messages e /var/log/secure podem ser verificados em busca de erros.

Habilitação de SSL (LDAPs)

Para que as informações não fiquem trafegando em texto plano, faz-se necessária a configuração de comunicação utilizando-se de SSL.Assume-se que, o AD já esteja com essa funcionalidade (LDAPS) habilitada.

Caso não, pode ser verificado em

Alterar o arquivo /etc/openldap/ldap.conf, para que ele não reclame do certificado de CA inválido apresentado pelo servidor:


Testar a comunicação com o comando abaixo (note que é o mesmo comando de teste anterior, chamando o protocolo LDAPS ao invés de LDAP apenas):

ldapsearch -v -x -H “ldaps://springfield.corp” -D “cn=AuthLinux,cn=Users,dc=Springfield,dc=corp” -b “dc=Springfield,dc=corp” -s sub -W

Conforme o teste funcione com sucesso, o arquivo /etc/nslcd.conf deverá ser alterado para permitir a utilização do SSL, alterando-se as seguintes linhas:

uri ldaps://springfield.corp
ssl yes
tls_cacertdir /etc/openldap/cacerts
tls_reqcert never

Reiniciar o NSLCD e o NSCD, e verificar o funcionamento com o:

# getent passwd USUARIO


Apesar de parecer complexa, a configuração de integração entre o GNU/Linux e o AD pode ser feita de forma bastante simples.

Esta é uma necessidade que muitas empresas têm, pois possuem seus controladores de domínio e, por diversas vezes, os seus servidores GNU/Linux não possuem uma forma de controle tão refinada quanto os servidores Windows.

Espero ter contribuído com qualquer necessidade.

Qualquer dúvida, estou à disposição. 😉

WiiMote no Linux com WMinput e WMgui

 Linux  Comentários desativados em WiiMote no Linux com WMinput e WMgui
ago 212012
Pré-requisitos e instalação

Nosso objetivo aqui é utilizar um Wiimote como mouse. Ótimo em apresentações que exigem a utilização do mouse, navegar pelo Google Earth e jogar jogos de tiro. =D


Requisitos opcionais:

Distribuição utilizada: Ubuntu 9.10


$ sudo apt-get install wminput wmgui

Visualização com WMgui

O WMgui é uma interface para visualizar as funcionalidades do Wiimote/Nunchuck/Classic.

Nele você conseguirá ver os:

  • Botões funcionando;
  • Sensores infra-vermelhos;
  • Sensores de movimentos;
  • Controles direcionais
  • Valores de aceleração(Accel), rotação(Roll), afastamento(Pitch);
  • Conteúdo da memória interna do WiiMote;
  • LEDs e controlá-los.

Vamos aos passos:

1. Conecte o adaptador bluetooth (parece um passo óbvio, mas perdi 2 minutos xingando o controle até lembrar desse passo primordial).

2. Abra um terminal e execute o “wmgui“.

3. FILE > CONNECT, abrirá uma janela.

4. Aperte os botões “1” e “2” do controle, para entrar em “Discovery Mode”.

5. Enquanto os LEDs do controle piscam, aperte OK na janela que foi aberta.

6. Habilite todas as funcionalidades do WMgui em SETTINGS.

7. Divirta-se!

Para testar o IR (Infra-Vermelho) sem uma lanterna IR, após habilitá-lo no SETTINGS, aponte um controle de TV (ou algo do tipo) e aperte os botões do controle.

No campo IR do wmgui deve aparecer uns pontos pretos. Se não possuir um controle, aponte para o sol! 😉

Mapeamento com WMinput

Com a configuração padrão o WMinput já funciona bem, porém o controle do mouse é feito baseado no acelerômetro.

Para testá-lo primeiro temos que subir o módulo UINPUT.

1. sudo modprobe uinput

2. Aperte “1”+”2″ no wiimote

3. sudo wminput


Já temos um protótipo funcionando.

Vamos ver mais a fundo os arquivos de configuração.

Todos os arquivos estão em /etc/cwiid/wminput/. Lá você encontrará:

  • default – Arquivo lido se não for especificado um arquivo de configuração. Link para acc_ptr
  • acc_ptr – Mouse baseado no acelerômetro
  • ir_ptr – Mouse baseado no infra-vermelho
  • gamepad – Configuração para usar o controle CLASSIC. – Não testei porque não tenho um… =(
  • nunchuk_acc_ptr – Mouse baseado no acelerômetro do Nunchuck
  • buttons – Mapeamento dos botões (outros arquivos incluem este em suas confs)
  • acc_led – Exemplo para acionar os LEDs do controle
  • fps_config – Uma configuração para jogos de tiro, vale a pena olhar e alterar
  • nunchuk_stick2btn – Configuração para utilizar o Nunchuck em jogos de tiro (Ex. Half-Life)
  • neverball – Teoricamente utiliza o acelerômetro de forma diferente, testei e não funcionou.

Teste com o infra-vermelho:

1. Coloque o LED IR na lanterna USB ou a pilha.

2. Ligue-a e posicione sobre ou sob o monitor.

3. Se você ainda não subiu módulo:

$ sudo modprobe uinput

4. Aperte “1”+”2″ no wiimote.

5. sudo wminput -c /etc/cwiid/wminput/ir_ptr

6. Assim que ele responder “Ready”, aporte para o LED e DIVIRTA-SE!

Caso apareça o seguinte erro:

Put Wiimote in discoverable mode now (press 1+2)…
No wiimotes found
unable to connect

1. Tire e coloque de novo a antena Bluetooth.

2. sudo wminput -c /etc/cwiid/wminput/ir_ptr

3. Aperte “1”+”2″ no wiimote.

4. Espere.

Às vezes ele demora uns segundos a mais para reconhecer, normal.

Migrando do PHP 4 para o PHP 5

 Clusterweb  Comentários desativados em Migrando do PHP 4 para o PHP 5
ago 212012

Essa sessão de faq ajudará a você migrar do PHP 4 para o PHP 5.

Migrando do PHP 4 para o PHP 5
Apesar do PHP 5 oferecer muitas vantagens novas, ele foi feito para ser o mais compatível possível com as versões anteriores com poucas funcionalidades sendo perdidas no processo.

Leia o apêndice de migração para o PHP 5 deste manual pois ele contêm ainda mais informações no tópico de migração para o PHP 5.

O MySQL funciona no PHP 5? Ele parece ter desaperecido.
MySQL é suportado com apenas a modificação de não ser mais habilitado por default in PHP 5. Isso essencialmente significa que o PHP não inclui a opção –with-mysql na linha configure então você deve fazer isso manualmente quando compilando o PHP. Usuários do Windows editarão php.ini e habilitarão a DLL php_mysql.dll já que no PHP 4 essa DLL não existia, era simplesmente montada no seus binários do PHP para o Windows.

Além disso, as bibliotecas de cliente do MySQL não são mais bundled com o PHP. Mais detalhes nesse tópico são abrangidas no seguinte FAQ e leia também a seção MySQL para detalhes sobre instalação do MySQL. Um exemplo de linha de configure seria –with-mysql=/usr enquanto usuários do Windows precisarão do arquivo libmySQL.dll disponível no sistema.

Eu ouvi que o PHP 5 tem um modelo de POO inteiramente novo, o meu código em POO já existente funcionará? Onde eu acho informação sobre essas novas caracterísicas de POO?
A principal mudança no PHP 5 é o modelo de POO já que o PHP 5 agora usa o Zend Engine 2.0. A diretiva zend.ze1_compatibility_mode permite compatibilidade com o Zend Engine 1.0 (PHP 4).

O novo modelo de POO está documentado nas seções OOP language reference e OOP migration appendix.

Então, além do novo modelo de POO, o que mais foi alterado no PHP 5? Além disso, existe numa versão específica do manual do PHP para a versão 5?
Algumas poucos modificações exitem, veja o apêndice 5 de migração para detalhes. Não haverá uma versão específica do manual do PHP para a versão 5 já que o cerne do PHP ainda é o mesmo.

Instalação automática do OCS Client usando GPO…

 Clusterweb, Linux, Redes  Comentários desativados em Instalação automática do OCS Client usando GPO…
ago 162012

Instalação automática do OCS Client usando GPO

Você que administra um rede com mais de 50 computadores sabe como é complicado fazer o controle do parque no que diz respeito as configurações e a localização dessas máquinas nos setores e seus usuários, para isso temos o OCS Inventory e o GLPI para ajudar com esse trabalho. Mas como tudo que é bom as vezes tras um pouco de trabalho, e o OCS não foge a regra. O OCS Inventory para coletar as informações, necessita que um aplicativo cliente seja instalado na máquina monitorada, para isso existem duas maneiras:

  1. Indo na máquina e instalando
  2. Fazendo isso automáticamente

Nesse artigo mostro como fazer uma das várias maneiras de instalação automatizada do aplicativo cliente do OCS Inventory. Vamos fazer este procedimento usando GPO do Active Diretory, mãos a obra.


1 – Criando um instalador personalizado

Para iniciarmos nosso processo, precisamos de um palicativo que encontra-se no site do OCS Inventory chamado OCS Packger, que pode ser baixado no seguinte link:

Outro programa que vai ser necessário para que este tutorial seja possivel é o executável do OCS Client, este pode ser baixado no link a seguir:

de posse desses dois aplicativos, vamos ao que interessa.

1.1 – Criando executável de auto instalação

Para iniciar o processo, vamos abrir o aplicativo OCS Packger, sua interface é bem simples e intuítiva, onde apenas dois campos vão ser preenchidos. A tela inicial e ela preenchida podem ser vista abaixo:

Os dois campos que vão usar para configurar o executável para a instalação automática, será o Exe file onde vai ser adicionado o caminho para o executável do OSC Client e o campo Command line options onde vai ser adicionado a seguinte linha de comando:


por fim é preciso adicionar o usuário com poderes administrativos para instalar a apalicação, nos dois ultimos campos desta tela. Caso queira usar um usuário do dominio adicione da seguinte maneira: DOMINIO\Administrador

Clique no botão Next, na proxima tela, adicione o local onde vai ser colocado o executável final.

Depois de escolher o local, clique no botão OK, neste momento vai ser iniciado o processo de criação do executável para ser adicionado no controlador de dominio, ao final do processo, uma tela será mostrada informando da criação com sucesso, clique em OK

Procure no local pelo arquivo gerado pela aplicação, neste processo demonstrado acima, ao encontra-lo, renomeie o mesmo para o ip do servidor onde esta instalado o OCS Inventory, como podemos ver no exemplo abaixo:

Com isso termina o primeiro passo, agora vamos configurar este aplicativo no controlador de dominio.

1.2 – Configurando GPO no Controlador de Dominio

Iniciando a configuração do controlador de dominio, primeiramente acesse seu controlador de dominio, abra o editor de GPO, neste exemplo está sendo usando o aplicativo Group Police Manager.

Agora, na pasta Group Police Objects, crie uma nova GPO clicando com o botão direito do mouse e coloque com um nome a sua escolha, neste exemplo dei o nome de OCS Cliente.

Com a GPO criada, clique com o botão direito e em seguida escolha a opção editar

A tela de configurações da GPO será aberta, como vista abaixo

Agora, vamos entrar em Configuração do computador, em seguida Configurações do Windows e por fim Scripts (inicialização/encerramento). No lado esquerdo existem duas opções, escolha a opção Inicializar, clique com o botão direito e escolha Propriedades.

A tela de propriedades vai ser aberta como vista abaixo, e nela vamos adicionar o arquivo de configuramos no primeiro passo desse artigo.

Nesta tela, clique em Adicionar…, vai ser mostrado uma nova tela, onde no primeiro campo vamos adicionar o caminho para o executável do aplicativo. Para isso clique no botão Procurar…

A tela abaixo mostra um diretório onde devemos colocar o arquivo criado, então, caso tenha criado o arquivo em um outro computador que não tenha sido o controlador de dominio, transfira o arquivo para o computador servidor, em seguida localize este arquivo e copie ele para dentro desta pasta, ficando como mostra a figura:

depois é só clicar em Abrir e voltaremos a telaanterior. Para finalizar vamos adicionar a seguinte linha de comando descrita abaixo no segundo campo disponível.


então esta tela ficará com a seguinte configuração:

Agora é só clicar em OK e confirmar as telas seguintes e lincar a gpo criada as OU’s que vão recebe-la. Espeque que as diretivas sejam atualizadas nas máquinas cliente e quando estas logarem novamente no servidor, o OCS Cliente sera instalado antes mesmo de aparecer a tela para inserir usuário e senha.

3 – Considerações finais

  1. A linha de comando descrita neste exemplo, pode ser alterada a seu gosto;
  2. Todo procedimento foi executando no Windows Server 2003 R2, então não sei se este mesmo passo a passo se aplica a versão Server 2008, mas acredito que sim;
  3. Se já existir alguma instalação anterior do OCS Cliente na máquina adiciono o string /FORCE na linha de comando para que ele force a sincronização
  4. Após instalado o OCS Cliente automaticamente já inicia a varredura dos componentes da máquina e as envia para o servidor, caso isso não ocorra, pode ter acontecido duas coisas:
    1. A versão do cliente não esta compativel com a versão servidor ( A versão mais nova não estável do cliente não funcionou corretamente comigo)
    2. A linha de comando não esta feita para a realidade do seu servidor, então reveja a linha e altere para sua realidade.

Bom pessoal acho que é isso, espore que este artigo ajude vocês a diminuirem um pouco do trabalho no deploy desse aplicativo que sem sombra de dúvidas é uma maravilha e ajuda bastante a equipe de suporte.


ago 162012

Sumário ………………………………………………………………………………………………………… 2
Considerações Iniciais………………………………………………………………………………………3
Procedimentos Iniciais ……………………………………………………………………………………..3
Acessando com usuário root……………………………………………………………………………… 3
Configurando proxy…………………………………………………………………………………………3
Atualizando repositório…………………………………………………………………………………….4
Instalando Apache, PHP5, Mysql e php5-ldap……………………………………………………… 4
Testando PHP …………………………………………………………………………………………………6
Testando Mysql ………………………………………………………………………………………………6
Alterações Importantes……………………………………………………………………………………..7
Baixando o GLPI …………………………………………………………………………………………….8
Pré-instalação do GLPI …………………………………………………………………………………….8
Instalação do GLPI via browser …………………………………………………………………………9
Autenticação pelo AD (ldap)…………………………………………………………………………… 13
Configuração do LDAP………………………………………………………………………………….. 13
Instalação do OCSInventory……………………………………………………………………………. 15
Procedimentos Iniciais …………………………………………………………………………………… 15
Instalando o OCS………………………………………………………………………………………….. 16
Concluindo a instalação do OCS ……………………………………………………………………… 18
Tela Inicial…………………………………………………………………………………………………… 20
Anexo I – Mapeando um diretório do SO Windows…………………………………………….. 20
Anexo II – Restauração de base de dados já existente (GLPI) ……………………………….. 21
Anexo III – Restauração de base de dados já existente (OCS) ……………………………….. 21
Anexo IV – Recuperando a senha do administrador do GLPI………………………………… 22
Anexo V – Sincronizando usuários do AD com o GLPI……………………………………….. 23
Anexo VI – Habilitando Modo OCS no GLPI (Sincronização)……………………………… 24
Considerações Iniciais
1. Um servidor Controlador de Domínios AD que já esteja instalado e
2. Um computador com SO Ubuntu server 8.04 ou superior e acesso Root;
3. Que o técnico responsável tenha um mínimo de conhecimento em Linux;
4. Acesso a internet.
Procedimentos Iniciais
Antes de iniciarmos o processo de instalação e configuração do GLPI precisamos
verificar se algumas dependências já foram solucionadas, (isso imaginando que o GLPI
e o OCSInventory serão instalados no mesmo servidor), as dependências seriam as
 Um servidor Apache2
 Suporte a PHP4 ou superior no servidor web (Neste caso, usaremos o PHP5)
 Servidor de banco de dados MySQL
 Integração PHP LDAP
 SSH se caso, seja necessária alguma configuração remota ao servidor.
Acessando com usuário root
É necessário acesso root para todas as instalações, para isso no console do Ubuntu
Server digite:
sudo su (ENTER) e logo após digite a senha de acesso root (ENTER)
OBS. Verifique se o prompt está com # que indica acesso root.
Configurando proxy
Se necessário autenticação em algum servidor proxy, é imprescindível o seguinte
comando para futuras instalações e download’s.
Digite: export http_proxy=“http://usuário:senha@domínio:8080” (ENTER)
Logo após, deve ser editado o arquivo hosts da seguinte forma:
Digite: nano /etc/hosts
Acrescente a linha: ip_servidor nome_servidor (EX. ServerProxy).
Salve as alterações (CTRL + X, Y)
Atualizando repositório
Digite: apt-get update (ENTER)
Instalando Apache, PHP5, Mysql e php5-ldap
Digite: apt-get install apache2 php5 mysql-server-5.1 php5-mysql php5-ldap php5-dev
php5-gd php5-mcrypt libapache2-mod-php5 (ENTER)
Obs: verificar se não existem versões superiores no repositório. Você pode usar o
comando EX: apt-cache policy php5, para verificar as versões instaladas e atuais do
repositório, ou apt-cache search nome_programa para busca por nome no repositório.
Na tela de configuração do Mysql que abrirá automaticamente, digite a senha “root” do
Redigite a senha
Escolha a opção Site Internet
Testando PHP
Verifique se contém em /home/viaza132/www o arquivo index.php (O acesso pode ser via browser,
digitando o ip_servidor).
Testando Mysql
Verifique se o Mysql foi instalado digitando: mysql –u root –p (senha root configurada
Utilize o comando exit; para sair
Alterações Importantes
Para evitar que a mensagem “Allocated memory: 16777216 octets A minimum of
32MB is commonly required for GLPI. Try increasing the memory_limit
parameter in the php.ini file.” seja mostrada no momento da instalação do GLPI, vai
ser necessário alterar no arquivo “php.ini” que está localizado no diretório
“/etc/php5/apache2/” o campo “memory_limit“.
Digite: nano /etc/php5/apache2/php.ini (ENTER)
Altera o campo memory_limit = 64M
OBS. Você pode buscar a linha utilizando o Pesquisa do nano (CTRL + W) = 16m
Salve as alterações (CTRL + X, Y)
É necessário o restart do apache para que as alterações sejam efetuadas, para isso
Digite: /etc/init.d/apache2 restart
Solucionado os pontos acima, vamos iniciar o download e a instalação do GLPI
Baixando o GLPI
A versão estável atual (agosto/2009) é GLPI 0.72.1 e está disponível em:
Pré-instalação do GLPI
Copie a pasta do glpi para /home/viaza132/www com o seguinte comando:
Digite: cp /local_da_pasta_glpi /home/viaza132/www –r (ENTER)
Obs. Você pode utilizar o comando tar caso queira descompactar o arquivo baixado
diretamente no local desejado. (Ex. tar -xzvf /mnt/suporte/glpi. –C /home/viaza132/www )
Confira se o conteúdo glpi foi copiado corretamente.
Digite: cd /home/viaza132/www/glpi (ENTER)
É indispensável dar permissões em algumas pastas e arquivos, para isso, você
pode dar permissão na pastas inteiras utilizando o comando chmod 777
/home/viaza132/www/glpi/files/ -r e chmod 777 /home/viaza132/www/glpi/config/ -r
Ou somente nos arquivos relacionados à abaixo (recomendado):
Digite: chmod 777 /home/viaza132/www/glpi/files/
chmod 777 /home/viaza132/www/glpi/config/
chmod 777 /home/viaza132/www/glpi/files/_dumps
chmod 777 /home/viaza132/www/glpi/files/_sessions
chmod 777 /home/viaza132/www/glpi/files/_cron
chmod 777 /home/viaza132/www/glpi/files/_cache
chmod 777 /home/viaza132/www/glpi/files/_log
Instalação do GLPI via browser
No Browser de qualquer Desktop da rede, acesse a URL: ip_servidor/glpi (caso não
saiba o ip_servidor, utilize o comando ifconfig para obtê-lo)
Neste Exemplo, o ip_servidor é
Configure conforme figuras a seguir:
Escolha a opção Português do Brasil (pt_BR) e clique em OK
Marque a opção ACEITO e clique em Continuar
Escolha a opção Instalar
Verifique se todas as permissões estão OK (bolinha verde), caso não esteja (bolinha
vermelha), será necessário alterar as permissões do arquivo/pasta que estiverem
faltando. Tudo OK, clique em Continuar.
Identifique o servidor Mysql juntamente com o usuário e senha root do Mysql. Neste
caso, o nome do servidor será localhost. Clique em Continuar
Vamos criar um novo database com o nome glpi (minúsculo). Clique em Continuar
Clique em Continuar
Clique em Use GLPI
O primeiro login será glpi e a primeira senha de acesso administrador também será glpi.
Pronto! O glpi foi instalado corretamente.
Autenticação pelo AD (ldap)
Novamente no Browser de qualquer Desktop da rede, acesse a URL: ip_servidor/glpi,
no menu Configurar, clique em Autenticação.
Selecione a opção Diretório LDAP
Clique sobre o botão + para adicionar um link a um AD já existente, e configure,
conforme informações do AD utilizado por você.
Configuração do LDAP
Clique sobre o Hiperlink Active Directory para ele preencher alguns campos
Nome: Nome do domínio (Pode ser colocado o nome de sua empresa)
Servidor: xxx.xx.xx.xx (Ip do servidor windows com AD)
Basedn: dc=dominio;dc=com;dc=br (enderço no formato ldap)
Pass(para conexão não anonima): ***** (senha administrador ou usuário do AD)
Filtro de Conexão: (objectClass=user)
Porta LDAP (default=389): 389
rootdn (para conexão não anônima): cn=user;ou=infra,dc=dominio;dc=com;dc=br
(você pode usar também seu usuário e senha do AD domínio\usuário)
Campo de Login: samaccountname
Usa TLS: Não
Fuso horário: GMT-3 hora(s)
Como os alias do LDAP devem ser manipulados: Nunca dês-referenciado (Por
Tipo de busca: Em usuários
Filtro para pesquisa em grupos: (objectclass=users)
usar DN na pesquisa: Sim
Usuários contendo seus grupos: memberof
Sobrenome: cn
Comentários: info
Telefones: telephonenumber
Celular: mobile
Nome: givenname
E-mail: mail
Telefones 2: otherstelephone
Os demais campos podem permanecer como estão.
Exemplo de configuração na figura a seguir (Detalhes de importação de usuários do AD
em anexo V).
Exemplo de AD configurado
Pronto! O GLPI já foi instalado com sucesso, e já está comunicando com o AD de rede.
Veja detalhes de Integração do GLPI e OCS-NG no anexo VI deste tutorial.
Instalação do OCSInventory
Procedimentos Iniciais
Antes de iniciarmos o processo de instalação e configuração do OCS precisamos
verificar se algumas dependências já foram solucionadas. O OCS necessita do módulo
PERL instalado para seu pleno funcionamento, para instalá-lo execute os seguintes
apt-get install build-essential libxml-simple-perl libcompress-zlib-perl libdbiperl
libdbd-mysql-perl libapache-dbi-perl libnet-ip-perl libsoap-lite-perl libphp-pclzip
aptitude install libxml-parser-perl
Também é necessário instalar o pacote CPAN manualmente, se você utiliza um
servidor proxy é preciso antes configurá-lo utilizando o comando
export http_proxy=“http://usuário:senha@domínio:8080” (ENTER).
Digite: perl -e shell -MCPAN
CPAN> install XML::Entities
Utilize o comando exit para sair da aplicação.
É necessário o restart do apache para que as alterações sejam efetuadas, para isso
Digite: /etc/init.d/apache2 restart
Instalando o OCS
Localize a pasta onde contém os arquivos de instalação e execute o instalador do OCS,
neste exemplo, o OCS já foi descompactado diretamente na pasta /root:
Digite: tar -xzvf /mnt/linux/…/ -C /root/
Digite: cd OCSNG_UNIX_SERVER-1.02.1
Siga os passos a seguir?
Do you wish to continue ([y]/n)? (ENTER)
Which host is running database server [localhost] ? (ENTER)
Do which port is running database server [3306] ? (ENTER)
Where is Apache daemon binary [/usr/sbin/apache2] ? (ENTER)
Where is Apache main configuration file [/etc/apache2/apache2.conf] ? (ENTER)
Which user account is running Apache web server [www-data] ? www-data
Which user group is running Apache web server [www-data] ? www-data
Where is Apache Include configuration directory [/etc/apache2/conf.d] ? (ENTER)
Where is PERL Intrepreter binary [/usr/bin/perl] ? (ENTER)
Do you wish to setup Communication server on this computer ([y]/n) ? (ENTER)
Where to put Communicarion server log directory [/var/log/ocsinventory-server] ?
Do you wish to continue ([y]/n) ? (ENTER)
Do you allow Setup renaming Communicarion Server Apache configuration file to ‘zocsinventory-
server.conf’ ([y]/n) ? (ENTER)
Do you wish to setup Administration Server (Web Administration Console) on this
computer ([y]/n) ? (ENTER)
Do you wish to continue ([y]/n) ? (ENTER)
Where to copy Administration Server static files for PHP Web Console
[/usr/share/ocsinventory-reports] ? (ENTER)
Where to create writable/cache directories for deployment packages and IPDiscover
[/var/lib/ocsinventory-reports] ? (ENTER)
Crie um database com o nome oscweb para receber as tabelas do banco de dados, para
Digite: mysql –u root –p (Digite a senha root do mysql) (ENTER)
Create database ocsweb;
Para verificar se foi criado utilize o comando show databases;
Utilize o comando exit para sair.
Concluindo a instalação do OCS
No Browser de qualquer Desktop da rede, acesse a URL:
ip_servidor/ocsreports/install.php (caso não saiba o ip_servidor, utilize o comando
ifconfig para obtê-lo e se necessário for “restartar” o sistema, utilize o comando reboot).
Neste caso, o ip_servidor é
Configure conforme figuras a seguir:
Utilize a senha root do mysql, criada no momento de sua instalação.
Clique em Enviar Consulta
Clique em Click here to enter OCS-NG GUI
Utilize login: admin e senha: admin para entrar. Caso tenha sido utilizado um backup do
database, utilize a senha administrador do database restaurado.
Tela Inicial
Pronto! O OCSInvetory já foi instalado com sucesso.
Anexo I – Mapeando um diretório do SO Windows
Caso seja necessário acesso a um diretório em um sistema operacional Windows é
preciso o pacote para comunicação (smbfs), que torna possível o acesso a arquivos em
diretórios Microsoft Windows.
Digite: apt-get install smbfs
Para mapear a pasta desejada:
Digite: smbmount //ip_do_compuador/nome_da_pasta /mnt/ -o username=usuário
(Talvez seja necessário digitar a senha do AD ou usuário local) (ENTER)
A pasta mapeada ficará em /mnt, para acessá-la:
Digite: cd /mnt/nome_da_pasta/ (ENTER)
ls (ENTER)
Anexo II – Restauração de base de dados já existente (GLPI)
Se você já tem uma base de dados “alimentada” do glpi, é possível restaurar/substituir a
base de dados em branco pela sua base de dados.
No console do Ubuntu Server:
Digite: mysql –u root –p glpi < /local_database/database.sql
(Digite a senha root do mysql) (ENTER)
Obs: Lembre-se que para isso, as versões do GLPI devem ser similares, tendo
em vista que pode haver mudança na estrutura das tabelas do banco utilizado por
versões diferentes.
Anexo III – Restauração de base de dados já existente (OCS)
Se você já tem uma base de dados “alimentada” do OCS, é possível restaurar/substituir
a base de dados em branco pela sua base de dados.
No console do Ubuntu Server:
Digite: mysql –u root –p ocsweb < /local_database/database.sql
(Digite a senha root do mysql) (ENTER)
Anexo IV – Recuperando a senha do administrador do GLPI
É possível substituir a senha admin da base de dados (database.sql), caso você não tenha
a senha administrador atual, para isso:
Digite: mysql –u root –p(Digite a senha root do mysql)
use glpi;
update glpi_users set password_md5=MD5 ( ‘glpi’ ) where name=’admin’;
Neste caso, o login foi restaurado para admin e a senha para glpi.
Utilize o comando exit; para sair.
É necessário o restart do apache para que as alterações sejam efetuadas, para isso
Digite: /etc/init.d/apache2 restart
Anexo V – Sincronizando usuários do AD com o GLPI
No usuário administrador do GLPI, na aba ADMINISTRAÇÃO, clique em
Clique na aba LINK LDAP.
Selecione o usuários que deseja importar do AD.
Clique em IMPORTAR.
Pronto! Os usuários já foram importados com sucesso.
Anexo VI – Habilitando Modo OCS no GLPI (Sincronização)
Na aba CONFIGURAR, clique em GERAL.
Na aba RESTRIÇÕES, coloque SIM para “Ativar modo OCS-NG”.
Configure conforme seu servidor OCS, exemplo a seguir:
Na aba FERRAMENTAS, clique em OCS-NG.
Utilize a opção “Importação de novos computadores” para sincronizar base de dados
com o OCSInventory.
Pronto! O modo OCS-NG já foi implantado com sucesso no GLPI.

TextMate 2 at GitHub

 Clusterweb  Comentários desativados em TextMate 2 at GitHub
ago 102012
  1. 1 Preface
    1. 1.1 About the Documentation
    2. 1.2 Philosophy of TextMate
    3. 1.3 Terminology
    4. 1.4 Limitations
  2. 2 Working With Multiple Files
    1. 2.1 Creating Projects (With Tabs)
      1. 2.1.1 Auto-Updating Projects
      2. 2.1.2 Filtering Unwanted Files
      3. 2.1.3 Text and Binary Files
      4. 2.1.4 Positioning the Project Drawer
    2. 2.2 Find and Replace in Projects
    3. 2.3 Moving Between Files (With Grace)
  3. 3 Navigation / Overview
    1. 3.1 Bookmarks
    2. 3.2 Collapsing Text Blocks (Foldings)
      1. 3.2.1 Customizing Foldings
    3. 3.3 Function Pop-up
      1. 3.3.1 Customizing the List
  4. 4 Working With Text
    1. 4.1 Auto-Paired Characters (Quotes etc.)
    2. 4.2 Completion
    3. 4.3 Copy and Paste
      1. 4.3.1 Clipboard History
      2. 4.3.2 Re-indented Paste
    4. 4.4 Editing Modes
      1. 4.4.1 Freehanded Editing
      2. 4.4.2 Overwrite Mode
    5. 4.5 Find and Replace
      1. 4.5.1 Inserting Newlines and Tabs in the Find Dialog
      2. 4.5.2 Find Clipboard
    6. 4.6 Moving Text
      1. 4.6.1 Increase/Decrease Indent Level
      2. 4.6.2 Move Text Up/Down/Left/Right
      3. 4.6.3 Re-indent Text
    7. 4.7 Selecting Text
      1. 4.7.1 Editing Multiple Lines
      2. 4.7.2 Column Selections
    8. 4.8 Column Movement / Typing
    9. 4.9 Smart Tab Behavior
    10. 4.10 Spell Checking
    11. 4.11 Using Spaces Instead of Tabs
  5. 5 Bundles
    1. 5.1 Activation of Bundle Items
      1. 5.1.1 Key Equivalents
      2. 5.1.2 Tab Triggers
    2. 5.2 Editing Default Bundles / Items
    3. 5.3 Deleting Default Bundles / Items
    4. 5.4 Hiding Bundles
    5. 5.5 Sharing Bundles and Bundle Items
    6. 5.6 Assorted Bundles
      1. 5.6.1 Diff
      2. 5.6.2 HTML
      3. 5.6.3 LaTeX
      4. 5.6.4 Source
      5. 5.6.5 SQL
      6. 5.6.6 Subversion
      7. 5.6.7 Text
      8. 5.6.8 TextMate
      9. 5.6.9 Xcode
    7. 5.7 Getting More Bundles
      1. 5.7.1 Installing Subversion
      2. 5.7.2 Setting LC_CTYPE
      3. 5.7.3 Installing a Bundle
      4. 5.7.4 Support Folder
      5. 5.7.5 RSS Feed With Bundle Change Log
  6. 6 Macros
  7. 7 Snippets
    1. 7.1 Plain Text
    2. 7.2 Variables
    3. 7.3 Interpolated Shell Code
    4. 7.4 Tab Stops
    5. 7.5 Placeholders
    6. 7.6 Mirrors
    7. 7.7 Transformations
  8. 8 Shell Commands
    1. 8.1 Executing Commands / Filtering Text
    2. 8.2 Search Path
  9. 9 Environment Variables
    1. 9.1 Dynamic Variables
    2. 9.2 Static Variables
    3. 9.3 Context Dependent Variables
    4. 9.4 Project Dependent Variables
  10. 10 Commands
    1. 10.1 Command Input
    2. 10.2 Command Output
    3. 10.3 HTML Output
    4. 10.4 Changing Output Type
    5. 10.5 Useful bash Functions
    6. 10.6 Dialogs (Requesting Input & Showing Progress)
  11. 11 Drag Commands
  12. 12 Language Grammars
    1. 12.1 Example Grammar
    2. 12.2 Language Rules
    3. 12.3 Rule Keys
    4. 12.4 Naming Conventions
  13. 13 Scope Selectors
    1. 13.1 Element Names
    2. 13.2 Descendant Selectors
    3. 13.3 Excluding Elements
    4. 13.4 Grouping
    5. 13.5 Ranking Matches
  14. 14 Themes
    1. 14.1 Sharing
  15. 15 Preferences Items
    1. 15.1 Completions
    2. 15.2 Indentation
    3. 15.3 Symbol List
    4. 15.4 Paired Characters
    5. 15.5 Other
  16. 16 Key Bindings
    1. 16.1 Bundle Items
    2. 16.2 Menu Items
    3. 16.3 Text Move / Edit Actions
      1. 16.3.1 List of Standard Key Bindings
    4. 16.4 Conventions
  17. 17 Templates
  18. 18 Printing
  19. 19 Saving Files
    1. 19.1 Atomic Saves
    2. 19.2 Creator Code
    3. 19.3 Encoding
    4. 19.4 Extended Attributes (Metadata)
    5. 19.5 Save Automatically when Focus Is Lost
  20. 20 Regular Expressions
    1. 20.1 Introduction
      1. 20.1.1 External Resources
    2. 20.2 Regular Expressions in TextMate
    3. 20.3 Syntax (Oniguruma)
    4. 20.4 Replacement String Syntax (Format Strings)
      1. 20.4.1 Captures
      2. 20.4.2 Case Foldings
      3. 20.4.3 Conditional Insertions
      4. 20.4.4 Escape Codes
  21. 21 Calling TextMate from Other Applications
    1. 21.1 Shell / Terminal
      1. 21.1.1 The General EDITOR Variable
      2. 21.1.2 Git Editor
      3. 21.1.3 TeX Editor
      4. 21.1.4 Edit from less
    2. 21.2 URL Scheme (HTML)
    3. 21.3 ODB Editor Suite
    4. 21.4 Cocoa Text Fields
  22. 22 Expert Preferences
    1. 22.1 NSDragAndDropTextDelay
    2. 22.2 NSRecentDocumentsLimit
    3. 22.3 OakBundleItemsPopUpMenuKeyEquivalent
    4. 22.4 OakBundleManagerDisambiguateMenuFontSize
    5. 22.5 OakDefaultBundleForNewBundleItems
    6. 22.6 OakDefaultLanguage
    7. 22.7 OakDisableSessionRestore
    8. 22.8 OakDocumentCustomFSMetaData
    9. 22.9 OakDocumentDisableFSMetaData
    10. 22.10 OakFindPanelDisableHistory
    11. 22.11 OakToolTipMouseMoveIgnorePeriod and OakToolTipMouseDistanceThreshold
    12. 22.12 OakWrapColumns
    13. 22.13 OakWordsExcludedFromCapitalization
  23. 23 Getting Help
    1. 23.1 Mailing List
    2. 23.2 IRC Channel
    3. 23.3 Other Resources
      1. 23.3.1 TextMate Cheat Sheet
      2. 23.3.2 TextMate Tutorials
      3. 23.3.3 Screencasts
  24. 24 Appendix
    1. 24.1 Property List Format
      1. 24.1.1 Strings
      2. 24.1.2 Arrays
      3. 24.1.3 Dictionaries
    2. 24.2 Indentation Rules
      1. 24.2.1 Introduction
      2. 24.2.2 The System
      3. 24.2.3 Increase Pattern
      4. 24.2.4 Decrease Pattern
      5. 24.2.5 Increase Only Next Line
      6. 24.2.6 Ignoring Lines
    3. 24.3 Plug-in API

1 Preface

1.1 About the Documentation

The intended purpose of the documentation is to explain the main features of TextMate and to highlight features that may not be obvious to first time users. The documentation is not exhaustive.

You should have a good understanding of what a text editor is, in particular you should have some experience with Cocoa’s text edit control (used in TextEdit, Mail and Xcode). While TextMate does not use that control, it does mimic its behavior for the most part.

If you want to print this documentation then here is a printable version.

1.2 Philosophy of TextMate

From UNIX we get that Tasks and Trends Change. In concrete terms this means that instead of writing a command (in UNIX) to solve the problem at hand, we find the underlying pattern, write a command to solve problems of that type and then use that command in a script.

This gives us a command which we can re-use in the future for multiple problems of the same type. Since it is generally much easier (and more flexible) to piece together a script of different commands than it is to write a specific command the increase in productivity can be very large. This is especially true since we do not actually write the command in the first place, we use an existing command that has already been written for this type of problem.

There are two ways in which TextMate leverages that philosophy. First it has good shell integration, so if you are skilled in using the UNIX shell, you should love TextMate.

But more ambitiously, TextMate tries to find the underlying patterns behind automating the tedious, being smart about what to do and then to provide you with the functionality so that you can combine it for your particular needs.

Granted, TextMate is not the first text editor which tries to be broad, but from Apple we get the venerable Keep It Simple. So even users with little or no experience with scripting and regular expressions are able to customize TextMate in ways that no other editor would have allowed them to.

Having said that, the philosophy of TextMate is also to Educate the User. So to fully capitalize on what TextMate gives you, you should learn about regular expressions, you should understand TextMate’s scope, snippet system (also language grammars to some degree) and have an idea about the shell infrastructure provided (in particular environment variables, pipes and stdin/stdout).

1.3 Terminology

For the most part TextMate and this documentation abides by Apples terminology. Below is a table of terms that might be a source of misunderstanding.

Term Explanation
Caret The text insertion point.
Cursor Mouse pointer.
Document This refers to a file when it is loaded into TextMate (for the purpose of being edited). Old-timers often refer to this as the buffer.
Directory This is sometimes used instead of folder. Folder is mainly used when talking about the GUI and directory is used when talking about shell related things.

Generally TextMate and this documentation use the glyph representation of a key. Below is a table with most glyphs, the name of the key (as used in this documentation) and a short explanation.

Keyboard Viewer

If you are unsure about the location of a key, you can bring up the Keyboard Viewer, which you can add to the Input menu in the International pane of System Preferences.

Glyph Key Name Explanation
Control This key is generally in the lower left corner of the keyboard (and symmetrically placed on the right side). In addition to key equivalents, this key is also used with a mouse click to bring up context sensitive menus.
Option This is next to the control key and often bears the label Alt. You can hold down the option key while dragging with the mouse to select text rectangularly. It is also possible to place the caret beyond the end of a line by single-clicking the mouse while holding the down option key (⌥). Together with Shift, the option key does a (rectangular) selection to where you click.
Command The command key is also referred to as the Apple key since it has an apple symbol on it ().
Shift The Shift key should be well-known. When used together with a mouse click, it extends the selection.
Escape The escape key is generally in the upper left corner of the keyboard. This key can be used to dismiss (cancel) panels, which means dialogs and some (but not all) windows. In TextMate it is also used to cycle through completion candidates.
Enter The enter key is on the numeric keypad (and is not the same as return). On laptops it is fn-return.
Return The return key should be well known.
Forward Delete This is often just called delete and on the keyboard has a label of Del or Delete.
Backward Delete Often called backspace. On most keyboards this has a left pointing arrow on the key (←).
﹖⃝ Help The Help key is located above Forward Delete, but not all keyboards have it. Generally it has the word Help on the key, but it is also known as the Ins key.
Home The Home key scrolls to the beginning of the document, but does not move the caret.
End The End key scrolls to the end of the document, but does not move the caret.
Page Up Scrolls up a page without moving the caret. Using the option key will cause the caret to be moved. When used with Shift it will create a selection.
Page Down Scrolls down a page without moving the caret. Using the option key will cause the caret to be moved. When used with Shift it will create a selection.
Tab The Tab key is used to insert a tab character (or equivalent amount of spaces if soft tabs are enabled). In normal controls it advances the focus to the next control.
Back-tab The Back-tab key can be used by holding down Shift while pressing the normal Tab key.

1.4 Limitations

TextMate is a work-in-progress. One current key limitation (for non-Western users) is support for international input modes (e.g. CJK), proportional fonts, right-to-left text rendering and other (UniCode) features. As the author, I do understand the desire from users to have TextMate support these things, but currently proper support for this is a long-term to-do item.

And on the topic of limitations, I am also aware of the desire for (s)ftp integration, code hinting, split views, better printing, indented soft wrap, coffee making and literally hundreds of other user requests. You will be able to find my comments on most feature requests by searching the mailing list archive, but I do not give estimates or timeframes, other than what version number I plan for something to appear in.

2 Working With Multiple Files

2.1 Creating Projects (With Tabs)

In the current version of TextMate (1.5) file tabs are only supported when a project is created. Fortunately it is easy to create a project, namely by selecting File → New Project (⌃⌘N).

This opens a window which looks like the one below.

Project Window

It is possible to add files either by dragging them to the (project) drawer, or use the “Add Existing Files…” action in the project drawers action menu (the one with the gear icon).

Another way to create a project is by dragging files directly onto the TextMate application icon (shown e.g. in the dock). This is a shortcut for creating a new project consisting of these files.

One minor detail is that when creating a project this way, you will not be asked if you want to save the project, when it is closed.

The advantage of saving a project is to maintain state (e.g. which files were open) and to be able to quickly re-open a particular set of files. If you leave a (saved) project open when you quit TextMate, it will automatically re-open that project the next time you launch TextMate.

It is also possible to create projects from the terminal e.g. using the mate shell command.

2.1.1 Auto-Updating Projects

When you want to have your project mimic the files and folders on disk, you can drag a folder either onto the TextMate application icon, or into the project drawer.

TextMate will then create a folder reference where it automatically updates the contents of the folder when it changes on disk.

Project Window With Tabs

Currently updating is done when TextMate regains focus and can be slow for some network mounted disks, in which case you may want to settle for only adding individual files to the project (which can be grouped and re-ordered manually to mimic the structure on disk).

The refresh delay for network mounted disks will be addressed in a future release.

2.1.2 Filtering Unwanted Files

When using folder references, you may want to have certain files or folders excluded from the project. This can be done by changing the file and folder patterns found in Preferences → Advanced → Folder References.

Folder Reference Patterns

These are regular expressions which are matched against the full path of each file and folder. If the pattern does match the item, it is included, otherwise it is excluded. To reverse that, so that items which match are excluded from the project, prefix the pattern with an exclamation point (!).

The patterns are only used when creating new folder references. For existing folder references one can select the folder reference in the project drawer and use the info button (a circled letter I) in the project drawer to edit the patterns.

The complexity of this system will be addressed in a future release.

2.1.3 Text and Binary Files

You can either single or double click files in the project drawer. If you single click them and the file type is text, they open as a file tab in the main window.

Tab Bar

If you double click a file, it will open using the default application. Note that folders can also be double clicked e.g. Interface Builder’s nib files will appear as folders, but can still be double clicked (and will then open in Interface Builder).

As mentioned, only text files will open in the main window when single clicked. The way TextMate determines if a file is text is by its extension – if the extension is unknown it scans the first 8 KB of the file to see if it is valid UTF-8 (which is a superset of ASCII).

If TextMate does not open your file and it does have an extension you can bring up the action menu for that file and pick the last item, which should read: Treat Files With “.«ext»” Extension as Text.

2.1.4 Positioning the Project Drawer

The project drawer will by default open on the left side of the project window. If there is no room for it to open there, it will use the right side instead. This setting is sticky so will remember which side the project drawer was last opened on.

Project Drawer

To move it back to the left side you need to close the drawer (View → Hide Project Drawer) and then move the project window so that there is no longer room for the drawer on its right. When you then re-open the drawer, it will again appear on the left side and use that as the new default.

The opposite can be done to force it to open on the right side.

2.2 Find and Replace in Projects

Using Edit → Find → Find in Project… (⇧⌘F) will bring up the window shown below.

Find In Project

From here it is possible to search all (text) files in the current project and do replacements. After pressing Find it is possible to either press Replace All, or select which matches should be replaced, in which case the Replace All button will change to Replace Selected.

Currently it is not possible to limit the scope of the search to anything other than all text files in the full project. As a workaround, when you want to search only a subset of your project, you can select the files you want to search in the project drawer and drag the selection to the TextMate application icon to create a new scratch project. A find/replace can then be performed on that project, which can then be closed.

2.3 Moving Between Files (With Grace)

When working with projects there are a few ways to move between the open files.

The most straightforward way is by clicking on the file tab you need. This can also be done from the keyboard by pressing ⌘1-9, which will switch to file tab 1-9.

You can also use ⌥⌘← and ⌥⌘→ to select the file tab to the left or right of the current one.

It is possible to re-arrange the file tabs by using the mouse to drag-sort them (click and hold the mouse button on a tab and then drag it to the new location). This should make it possible to arrange them so that keyboard switching is more natural.

One more key is ⌥⌘↑ which cycles through text files with the same base name as the current file. This is mainly useful when working with languages which have an interface file (header) and implementation file (source).

When you want to move to a file which is not open you can use the Go to File… action in the Navigation menu (bound to ⌘T). This opens a window like the one shown below.

Go To File

This window lists all text files in the project sorted by last use, which means pressing return will open (or go to) the last file you worked on. So using it this way makes for easy switching to the most recently used file.

You can enter a filter string to narrow down the number of files shown. This filter string is matched against the filenames as an abbreviation and the files are sorted according to how well they match the given abbreviation. For example in the picture above the filter string is otv and TextMate determines that OakTextView.h is the best match for that (by placing it at the top).

The file I want is which ranks as #2. But since I have already corrected it in the past, TextMate has learned that this is the match that should go together with the otv filter string, i.e. it is adaptive and learns from your usage patterns.

3 Navigation / Overview


If you need to move the caret to somewhere else in your document and want a quick way to return, you can place a bookmark on the current line.

This is done either by clicking in the gutter (in the column dedicated to bookmarks) or pressing ⌘F2. The bookmark will be indicated with a star as shown below.


When you want to return you can press F2, which moves you to the next bookmark in the document. If there is more than one bookmark, you can press F2 repeatedly. ⇧F2 will move to previous bookmark.

3.2 Collapsing Text Blocks (Foldings)

When working in a language which has start/end markers for blocks, like {}, doend, <tag></tag> and similar, TextMate can spot these blocks and will show up/down arrows in the gutter beside the start/end marker.

When these arrows are present, it is possible to fold the block into a single line either by using the mouse and clicking on the up/down arrow, or pressing the F1 key. This will make the arrow in the gutter point to the right and indicate that the entire block was folded by placing an ellipsis marker at the end of the line. An example where the two sub-blocks of the constructor has been folded can be seen below.

Folded Blocks

With text folded, it is possible to unfold it with F1 or clicking either the arrow in the gutter or the ellipsis image. It is also possible to hover the mouse pointer on the ellipsis image to get a tool tip which shows the contents of the folded block. The latter is shown on the following picture.

Folding Tool Tip

A word of caution: the folding system is based on both having clear indent markers and having the fold start/stop markers use the same indent level. This means that folding based purely on indent or where the start/stop markers do not align, is currently not supported.

3.2.1 Customizing Foldings

As mentioned the folding system uses explicitly defined start and stop markers. TextMate knows about these from the language grammar where you can setup a foldingStartMarker and foldingStopMarker regular expression.

Folding Patterns

Shown above are the HTML folding patterns, which are all relatively simple because they fold on a selected set of tag pairs, HTML comments, some Smarty tags and start/stop braces when either last on the line or used in embedded code tags like this:

<?php if(something) { // user is authenticated ?> ... <?php } // user is authenticated ?> 

To define a block that starts with { as the last non-space character on the line and stops with } as the first non-space character on the line, we can use the following patterns:

foldingStartMarker = '\{\s*$'; foldingStopMarker = '^\s*\}'; 

3.3 Function Pop-up

For languages that support it, the rightmost pop-up in the status bar shows the current “symbol” (often the function prototype or heading above the caret).

Status Bar

It is possible to click on the pop-up to get a list of all the symbols in the current document and move the caret to one of these. This is shown below.

Function Pop Up

For keyboard navigation there is also Navigation → Go to Symbol… (⇧⌘T) which opens a panel like the one shown below. The contents of this pane are the same as the pop-up from the status bar but this panel supports filtering similar to the Go to File… panel (i.e. where the filter string is treated as an abbreviation and matches are ranked according to how good a fit the abbreviation seems to be).

Symbol List

The panel can be left open and will automatically update as the document is edited. If you single-click an item in the list, the caret will move to the symbol clicked. Double-clicking will do the same but also closes the panel.

3.3.1 Customizing the List

The symbol list works using language grammars and scope selectors. A language grammar assigns names to each element in the document and a scope selector is capable of targeting a subset of the document based on these names. Normally the parallel is HTML and CSS, e.g. we can make a theme item which sets the background to blue and then use the scope selector to pick which elements in our document we want this theme (and hence the blue background) applied to.

Bundle preferences work like theme items, except that instead of changing visual settings they (generally) change non-visual settings. One exception is the showInSymbolList. By setting this to 1 and using a scope selector which (for example) targets all function names, we are using that scope selector as a query to extract all the function names from the document, for use in the symbol list.

So to populate the symbol list we need to:

  1. Make sure the language grammar assigns a name to what we want to show.
  2. Create a bundle preferences item that sets showInSymbolList to 1 and uses a scope selector that matches the symbols we want to have in the symbol list.

In addition to the showInSymbolList setting there is a symbolTransformation setting which is one or more regular expression substitutions which are performed on the text extracted. The value of this setting should be: s/«regexp»/«format»/«options» optionally followed by ; and more substitutions. It is also possible to put comments in the value, these start with # and end at the next newline.

So if we want to show Markdown headings in the list, which are lines that start with one or more # marks, then we first make sure our language grammar assigns a name to these, for Markdown that can be identified with this rule, by specifying the following in the language grammar:

{ name = 'markup.heading.markdown'; match = '^#{1,9}\s*(.*)$'; }, 

Now we can target all headings using a scope selector of markup.heading.markdown. We can now create a bundle preferences item that is simply:

{ showInSymbolList = 1; } 

This will include the leading # marks in the list, which is undesirable. We can either assign a name (via the language grammar) to the actual title, or we can perform a regular expression substitution to get rid of the leading # marks. The latter has the advantage that we can change these to indent, so that is what we do, by changing the preferences item to:

{ showInSymbolList = 1; symbolTransformation = ' s/(?<=#)#/ /g; # change all but first # to m-space s/^#( *)\s+(.*)/$1$2/; # strip first # and space before title '; } 

4 Working With Text

TextMate tries for the most part to mimic the behavior of the NSTextView system component, as used by applications such as Mail, Safari and basically all other Cocoa applications.

Some of the extra features related to text editing are covered in this section.

4.1 Auto-Paired Characters (Quotes etc.)

When writing structured text (like markup or source code) there are characters which go together in pairs. For example in a programming language you rarely type an opening brace ({) without also needing the closing brace (}).

To help you keep these characters balanced, TextMate will insert the appropriate closing character after the caret when you type the opening one. If you type the closing character TextMate is smart enough to overwrite the auto-inserted one. If you type an opening character and then delete it using backward delete (⌫) then the auto-inserted character will also be deleted. If you only want to delete the auto-inserted character, use forward delete instead (⌦).

It is also possible to wrap a selection in an open/close character by selecting text and typing the opening character. For example if you type foo, select it and type ( then TextMate will make it (foo) placing the caret after the ending parentheses.

The actual character pairs are defined in the bundle preferences with different settings for different languages and contexts. For example, in source code an apostrophe is set up to have itself as a closing character, except for comments and strings. This is achieved using scope selectors.

Two useful shortcuts in relation to auto-paired characters (defined as macros in the Source bundle and overridden for a few languages) are:

  1. ⌘↩
    Move to the end of the line and insert a newline.
    For example if you write:


    Then you will have ") to the right of the caret and can now use ⌘↩ to skip these two characters and insert a new line.

  2. ⇧⌘↩
    Move to the end of the line, insert a ; and then insert a newline.

4.2 Completion

TextMate has a simple yet effective completion function on ⎋ (escape). It will complete the current word based on matches in the current document. If there are multiple matches, you can cycle through these by pressing ⎋ continuously. It is also possible to cycle backwards using ⇧⎋.

The matches are sorted by distance from the caret, meaning candidates which are closer to the caret will be suggested before candidates farther away.

Two possibilities exist for augmenting this default completion. Both are done via bundle preferences.

The first option is to provide a list of candidates which should always be suggested. For example the Objective-C bundle has a list of commonly used Cocoa framework methods. This is an array of the candidates, e.g.:

completions = ( 'retain', 'release', 'autorelease', 'description' ); 

The other option is to set a custom shell command to gather the completions. The shell command will have the TM_CURRENT_WORD environment variable available (as the word which needs to be completed) along with the other variables.

For example the C bundle has a custom completion command setup for when the caret is inside the preprocessor include directive, it looks like this:

completionCommand = 'find "$TM_DIRECTORY" \ -name "$TM_CURRENT_WORD*.h" -maxdepth 2 \ -exec basename "{}" \;|sort'; 

This will find as matches, any file in the current directory (and direct sub-directories) which have the current word as prefix and an .h extension.

When you provide your own completion command (or list) you may want to disable the default matches. This can be done by setting disableDefaultCompletion to 1.

4.3 Copy and Paste

4.3.1 Clipboard History

Each time you copy or cut text, the text is pushed onto a stack.

By pressing ⌃⌥⌘V you will see the list of all previous clippings and can pick the one you want to paste using arrow keys. Use return to insert it and escape to dismiss the list. If you dismiss the list, the currently selected clipping will be what gets pasted the next time you use the paste function.

Clipboard History

Instead of having to pick the clip from the list, you can use ⇧⌘V to paste the previous clip in the list. Using that key again will advance to the clip before that and so on. To go back you can use ⌥⌘V. These key equivalents are useful when you want to make multiple copies from one document and then paste these LIFO-style (Last In First Out) into another document (or another location in the same document).

4.3.2 Re-indented Paste

When pasting text, TextMate will estimate the indent of the text pasted as well as the current indent level and adjust the pasted text so that it matches the current indent.

The estimates are done using the indentation rules mentioned in the Re-Indent Text section.

If you temporarily want to avoid this you can paste text using ⌃⌘V. You can also permanently disable re-indented pasting in the Text Editing part of the Preferences.

4.4 Editing Modes

4.4.1 Freehanded Editing

You can enable or disable freehanded editing in the Edit → Mode submenu (⌥⌘E).

With this mode enabled caret movement will not be restricted by line endings or tab stops.

This is useful when working with ASCII diagrams, when inserting something at a given column on several lines (and you do not want to insert the padding) and in a few other situations.

When making column selections freehanded mode is (temporarily) enabled, allowing you to make selections past the end of lines.

It is also possible to place the caret beyond the end of a line by single-clicking the mouse while holding down the option key (⌥).

4.4.2 Overwrite Mode

By enabling overwrite mode in the Edit → Mode submenu (⌥⌘O) characters already in the document will be overwritten as you type rather than inserted as normal.

This is useful when working with column data, e.g.:

foo jaz bar sub fud dub 

Imagine we want to overwrite some of the values in the first column. Somewhat similarly, we may have a line of a fixed width and want to replace part of it but preserve the width, for example we could have code like this where we must right-align the value to column 20 but want to overwrite the label:

printf("Value is %3d", 37). 

4.5 Find and Replace

In addition to the standard find dialog, TextMate has a Find submenu (located in the Edit menu) which gives you key equivalents for find and replace actions.

Find Menu

4.5.1 Inserting Newlines and Tabs in the Find Dialog

The find dialog uses normal system controls for accepting input. You can toggle between single line and multi line text controls using the arrow next to the Replace text field.

Multi Line Find Dialog

If you need to insert a newline or tab character into either of the text fields, you can hold down option (⌥) while pressing the tab (⇥) or return (↩) key. This will insert a literal tab or newline character.

4.5.2 Find Clipboard

Two useful key equivalents are ⌘E and ⌘G. The first copies the selection to the shared find clipboard. This works in the majority of applications and allows you to find the next occurrence of that string by then pressing ⌘G.

The find clipboard works across applications so whether in Safari, TextEdit, Mail, TextMate, Terminal, Console, or similar, one can copy the selected text to the find clipboard, switch application and use ⌘G to find that string.

In addition TextMate offers ⇧⌘E to copy the selection to the replace clipboard. This is often useful to save a trip to the find dialog, for example if you want to replace newlines with the pipe character (|) for a list of items, select a newline, press ⌘E to use that as the find string. Now type a |, select it and press ⇧⌘E so that it is copied to the replace clipboard.

The next step is then to either press ⌃⌘F to perform the replacement in the entire document, or select the range in which you want the replacement to occur and use ⌃⇧⌘F instead.

4.6 Moving Text

4.6.1 Increase/Decrease Indent Level

In the Text menu there is a Shift Left and Shift Right action bound to ⌘[ and ⌘]. These will increase and decrease the indent by the size of one tab.

On many european key layouts these keys are rather awkward, so in addition to these, you can also use ⌥⇥ and ⌥⇤ (where ⇤ is achieved using ⇧⇥).

4.6.2 Move Text Up/Down/Left/Right

If you want to move a line/block up/down a few lines or move a word/column selection, it can be done by holding down ⌃⌘ and using the arrow keys to move the selection around. It also works for moving lines up/down without a selection.

4.6.3 Re-indent Text

If you have code which has broken indent, you can select it and use Text → Indent Selection (without a selection it indents the current line).

The rules for estimating the indent are setup per-language using bundle preferences. For more details see the indentation rules section.

4.7 Selecting Text

Selecting text is achieved by holding down ⇧ while using the normal movement keys. In addition the Edit → Select submenu has actions to select current word, line, paragraph, enclosing brackets and entire document.

4.7.1 Editing Multiple Lines

Sometimes there is a need for adding a suffix to lines of variable length, or maybe editing the last part of these lines.

Although you can use find and replace for this, an easier way is to select the lines that needs to be edited, then use Text → Edit Each Line in Selection (⌥⌘A) and the caret will be placed at the end of the first line in the selection.

You can now type new text, delete text or go back and edit existing text and this will be mirrored down through all the (previously selected) lines. To leave this mode, simply move the caret away from the current line.

4.7.2 Column Selections

It is possible to select column data either by holding down ⌥ and making the selection with the mouse, or making a regular selection and then pressing ⌥ once (which toggles between the two types of selection).

You can use all the normal actions on a column selection e.g. move selection, replace in selection, transpose (lines), actions from the Text menu, filter the selection through a shell command, etc.

4.8 Column Movement / Typing

Using arrow up/down with ⌥ will move the caret to the first/last row in the current column. Hold down ⇧ to get it selected.

Column Data

For example if you have column data as shown above with the caret in front of foo, press ⌥⇧↓ and it will move the caret down in front of fud and leave the text between foo and fud selected.

Column Movement

You may now either want to press ⌥ once to switch to a zero-width column selection, then start typing to type on each line.

Column Typing

Alternatively use ⌥⇧→ and then ⌥ to leave the entire column selected (in column mode).

Column Selection

4.9 Smart Tab Behavior

When using the tab key at the beginning of a line, TextMate will insert as many tabs as it estimates to be correct for that line. If the line already has text the caret will move to the front of this text.

If the line already has the correct indent (or above) a single tab will be inserted.

4.10 Spell Checking

TextMate supports the system wide ‘Check Spelling as You Type’. This can be changed in the Edit → Spelling submenu.

You can bring up the context sensitive menu for a misspelled word to get spelling suggestions.

Since TextMate is intended for structured text it is possible to exclude parts of the document from being checked. This is done by creating a preferences item in the bundle editor, setting spellChecking to 0 and filling in the scope selector with the selector to target for no spell checking.

By default spell checking is disabled for source code except strings and comments and also for keywords, tags and similar in HTML, LaTeX, Markdown, etc.

4.11 Using Spaces Instead of Tabs

TextMate can use spaces instead of tab characters. This is done by clicking the “Tab Size” pop-up in the status bar and enabling Soft Tabs.

This setting will only affect the current language and all languages with a common root that do not have the option set yet. The same applies to the state of spell checking, soft wrap and the actual tab size.

Tab Size Settings

When soft tabs are enabled, TextMate will for the most part act exactly as if you were using hard tabs but the document does indeed contain spaces.

5 Bundles

A lot of functionality in TextMate is provided through various bundles, many of which are language specific.

The default bundles are located in /path/to/ Normally you do not need to care about this, as you inspect (and edit) the bundles through the bundle editor (which can be reached through the Window menu).

5.1 Activation of Bundle Items

If you select Bundles → Bundle Editor → Show Bundle Editor you will see the command center for customizing TextMate.

Bundle Editor

From this window you can create and edit things like snippets, commands, language grammars, etc. which will be explained in more detail in the following sections.

Most items edited in the Bundle Editor represent actions you want to execute while editing text. TextMate offers a few ways to do this and has a simple yet powerful system to understand the current context when evaluating which action the activation method should result in, called scope selectors, which is explained in a later chapter.

5.1.1 Key Equivalents

The easiest way to perform an action (from the keyboard) is in the form of a key equivalent. A key equivalent can be any key with optional modifiers and is configured by activating the key equivalent field and pressing the key to which the item should be bound.

Key Equivalent

If you want to disassociate a key equivalent with an item, press the X shown while the key equivalent field is in recording mode.

If multiple items are given the same key equivalent then a menu will appear when that key equivalent is pressed, as shown below (all of the items in the Math bundle are bound to ⌃⇧C so a menu with each key equivalent option is displayed).

Key Equivalent Ambiguity

5.1.2 Tab Triggers

As well as assigning a single key equivalent to a bundle item, it is possible to assign a tab trigger to the item. This is a sequence of text that you enter in the document and follow it by pressing the tab key (⇥). This will remove the sequence entered and then execute the bundle item.

For example the Text bundle has a snippet which inserts the current date conforming to ISO 8601 (YYYY-MM-DD). The tab trigger for this snippet is isoD (short for ISO Date). In your document it is thus possible to type isoD and press tab to “expand” that to the current date.

This allows you to create much better mnemonics for your bundle items as you can literally type the thing you want to execute (e.g. the snippet to insert). It is generally a good idea to use actual words instead of abbreviations (like use list instead of lst) since the purpose is to make it easier to remember, so the tab trigger should generally be the first thing that pops into your mind in the unabbreviated form.

Tab triggers are rendered in the right side of the menu item with a slightly rounded rectangle as background and the tab character (⇥) shown as a suffix to the tab trigger.

Tab Trigger Menu

Tab triggers are also useful when they match program keywords and lead to actions (such as inserting snippets) that do what you would normally do after entering the keyword. For example in Ruby a method starts with def so creating a snippet for a Ruby method and assigning it def as tab trigger gives a natural flow, as you would write def as usual and then use tab instead of taking the normal actions. Had the tab trigger for a method (in Ruby) instead been method or similar, it means you would have to remember “I can insert a snippet for this” before typing def, whereas with def as the tab trigger, you have to remember it before pressing the space after def (basically just pressing tab instead of space).

As with key equivalents, entering a tab trigger and pressing tab will show a menu, when multiple items share the same tab trigger. This can be used to provide a simple form of code-completion, for example in CSS the tab trigger list has been assigned to all properties that start with list. So in CSS typing list followed by tab will give a useful menu from where you can pick what list property needs to be inserted.

Tab Trigger Ambiguity

5.2 Editing Default Bundles / Items

Some of the default items may not be to your exact liking, for example the coding style in snippets may differ from yours, so you may want other tab triggers, key equivalents, or similar modifications.

If you edit a default item the difference will be stored in ~/Library/Application Support/TextMate/Bundles. These are then merged with the default version so your changes will be effective even after upgrading TextMate. All new items you create also end up in this location.

Bundles or bundle items which you install by dragging them to TextMate or double clicking will be installed in ~/Library/Application Support/TextMate/Pristine Copy/Bundles. Editing these will also result in only the differences being stored in ~/Library/Application Support/TextMate/Bundles, meaning that if you later get a new version of this third party bundle, you can safely install this one on top of the old one (by dragging it to TextMate) and again your changes will be preserved.

If you want to discard local changes then currently the only option is to delete these from ~/Library/Application Support/TextMate/Bundles.

5.3 Deleting Default Bundles / Items

You can also transparently delete default bundles and bundle items from the bundle editor. However, since the items are shipped with the TextMate application, they are not removed on disk, since they would then reappear after an upgrade.

Instead each bundle has an info.plist file which keeps the ordering of bundle items and also stores which of the default items should act as if they have been deleted. When you change the ordering of items in a default bundle or delete items, this file is copied to ~/Library/Application Support/TextMate/Bundles/«bundle name».tmbundle and will contain this info.

If you delete an entire bundle the information is recorded in TextMate’s preferences. You can get a list of which default bundles have been deleted by running the following line in terminal:

defaults read com.macromates.textmate OakBundleManagerDeletedBundles 

To reset the list of deleted bundles (i.e. undelete them) instead run this (while TextMate is not running):

defaults delete com.macromates.textmate OakBundleManagerDeletedBundles 

This may all sound a little complicated, but generally you should not care about these details. Just use the bundle editor to create, edit and delete your items and bundles and it should work as expected.

5.4 Hiding Bundles

Instead of deleting default bundles you may want to just hide them (since you never know if you someday will need some of the default ones).

This is done by clicking the Filter List… button below the list in the bundle editor. Here you can uncheck the bundles that you do not wish to have shown in the various lists of bundle items.

Hiding Bundles

5.5 Sharing Bundles and Bundle Items

If you want to share a bundle or particular bundle item then you can drag it directly from the bundle editor (from the list in the left side of the window) to the Finder.

This item can then be sent to other people and they will be able to double-click it to install it. Note: this also works for single items, like a snippet or a command.

5.6 Assorted Bundles

Often a bundle will provide support for a particular language (though there are exceptions like the Source, Text and TextMate bundles). To get a good idea of what features the bundle provides, it is best to investigate it in the bundle editor (accessible from the Windows menu). When appropriate, a language bundle should provide the following, with key bindings as shown:

  • Build (⌘B) — build the current source/project. Normally that means compile it.
  • Run (⌘R) — run the current source (script) or product from building a project.
  • Documentation for Word (⌃H) — lookup the current word (or “unit”) in the documentation (often online).
  • Validate Syntax (⌃⇧V) — run the syntax through whatever form of syntax checker exist for the current document type. Generally show errors as a tool tip, but for more complex validation, HTML output is sometimes used.
  • Wrap in «Something» (⌃⇧W) — wrap the selection in what makes sense for the current document type, e.g. open/close tags in HTML, begin/end environment in LaTeX.
  • Convert to «Something» (⌃⇧H) — convert the document into something which makes sense, e.g. for HTML run it through tidy, for Markdown convert it to HTML, for an XML property list convert it to the more readable ASCII version, etc. Generally this is done in-place, overwriting the current document.
  • Continue «Something» (⌅) — continue the current construct on the next line e.g. a line comment, list item or similar.
  • Preview Document (⌃⌥⌘P) — by default this opens the Web Preview, but it has been overloaded for some markup languages for a preview more suited for that language (i.e. doing the HTML conversion and setting up a basic style sheet before showing it).
  • Insert Close Element (⌥⌘.) — by default this inserts the appropriate closing tag (HTML) but is overloaded in some contexts to insert whatever constitutes a close element (e.g. \end{environment} in LaTeX).
  • Comment Toggle (⌘/) — toggle comment characters around the current line or selection.

Many bundles also have a Help command with some details about how to use and customize its functionality.

Bundle actions can be accessed through the gear pop-up in the status bar. This menu can also be brought up by pressing ⌃⎋.

Bundle Actions

Below are a few highlights from miscellaneous bundles.

5.6.1 Diff

The Diff bundle provides a language grammar for the output produced by the diff shell command.

You can show the differences between two files in TextMate by running the following command from your terminal:

diff -u old_file new_file|mate 

The bundle also has commands to show the differences between the current document and the saved copy, between the selected files in the project drawer (with an HTML output option) and it has a command to open the selected files in Apple’s FileMerge using opendiff (requires the developer tools to be installed).

5.6.2 HTML

The HTML bundle contains useful stuff for working with HTML. A few particularly useful actions are:

  • Insert Open/Close Tag (⌃<) — this command will take the word just typed and change it into <word></word> placing the caret in the middle. It will recognize those tags where a close tag is not allowed (like hr) and instead insert <word> placing the caret after the tag.
  • Wrap Selection in Open/Close Tag (⌃⇧W) — this will put <p>…</p> around the selection but allows you to overtype the p (and add arguments). After you are done, press tab to move the caret past the </p> tag.
  • Wrap Selection as Link (⌃⇧L) — this turns the selection into link text for an anchor where you can then fill in the URL.

The HTML bundle also has a drag command for images which insert the dropped image with proper dimensions (width/height) and an alternative text derived from the file name.

A lot of actions in the HTML bundle will cause tags to be inserted. E.g. pressing ⌃↩ inserts <br>, dropping an image on a HTML document inserts <img …>, etc.

If you want tags with an EMPTY content model to use the minimized (XHTML) form (that is <br /> instead of <br>) then in PreferencesAdvanced create a new variable named TM_XHTML and set it to ‘ /’ (the value of this variable will be inserted before the > in the generated tags with EMPTY content model).

For the records have a look at Sending XHTML as text/html Considered Harmful before embracing XHTML.

5.6.3 LaTeX

Three commands of special interest in the LaTeX bundle are:

  • Typeset & View (PDF) (⌘B) — this will run pdflatex on your current file, or TM_LATEX_MASTER (if that variable is set). If there were errors, these are shown as clickable links, otherwise the resulting PDF will be shown in the HTML output (requires Tiger or Schubert’s PDF Browser PlugIn).
  • Insert Environment Based on Current Word (⌘{) — this mimics the HTML bundles ⌃< in that it makes the current word into \begin{word} … \end{word} and places the caret in between. There are various configuration options for this command, for details see the Help command in the LaTeX bundle or the source for the command itself (via the Bundle Editor).
  • Insert Command Based on Current Word (⌘}) — like the previous command, but makes word into \word{} with the caret inside the braces.

If you have not installed LaTeX you can use the i-installer (binaries).

Alternatively, if you have MacPorts then open your terminal and run:

sudo port install teTeX 

5.6.4 Source

The source bundle contains default actions and preferences for source code. Of interest is the Comment Line / Selection (⌘/) which will toggle the comment characters for the current line or selection. This command is setup for different languages via three context dependent variables.

The various macros to go to end-of-line and insert the line terminator character (; by default) and/or a newline are also rather useful.

5.6.5 SQL

The SQL bundle has a command that can submit the current line or selection as a MySQL or Postgres query (⌃⇧Q) and show the result using HTML output.

It uses a few environment variables to store connection details. These are described in the bundle’s Help file.

5.6.6 Subversion

All actions in the subversion bundle are accessible through ⌃⇧A. These offer the commands which would be used in a common workflow.

None of the commands are made to prompt you for a password. For repositories offered through WebDav (i.e. http or https) svn should cache your authentication. This post describes how to generate an ssh key pair for secure-shell tunneling (ssh).

Subversion Commit

The commit action will commit the files selected in the project drawer or current file if there is no selection. The commit window also allows you to exclude files before doing the actual commit.

In the commit window you can use enter (⌅) to trigger the “Commit” button shown in the bottom right corner.

5.6.7 Text

The text bundle is for actions and preferences related to basic text editing. From a users perspective some of this should probably have a more native placement than being in a bundle.

The four probably most useful actions are:

  • Delete Line (⌃⇧K) — delete the current line.
  • Document Statistics (⌃⇧N) — this provides a tool tip which show how many lines, words and characters the current document contains.
  • Duplicate Line / Selection (⌃⇧D) — this will duplicate the current line, leaving the caret in the same column on the new line, or if there is a selection, duplicate that.
  • Sort Lines in Document / Selection (F5) — this will sort the lines or selection alphabetically.

5.6.8 TextMate

The TextMate bundle is kind of a meta bundle. That means none of the actions are for text editing but are instead intended for creating new bundle items, searching the mailing list archive, pasting the current selection to an IRC channel or similar.

Show Scope

One command which is useful when working on themes or language grammars is the Show Scope (⌃⇧P) which shows the current scope of the caret (more about scopes later).

5.6.9 Xcode

The Xcode bundle has actions to build the Xcode project located in the folder that contains the current document or project and to run the resulting target.

Build With Xcode

It also has commands to import an Xcode project but generally it is better to drag the folder with your Xcode project to the TextMate application icon, since currently the TM_PROJECT_DIRECTORY variable is not correctly setup for imported projects and a lot of bundle actions rely on this (e.g. the Subversion stuff).

5.7 Getting More Bundles

Only the most popular bundles are included with TextMate. There is a subversion repository which has dozens of other bundles mostly adding support for various languages. You can see the list of bundles here.

5.7.1 Installing Subversion

If you are not using Leopard you will need to install the subversion client.

  • If you have MacPorts then open your terminal and run:
    sudo port install subversion 
  • If you use Fink then install the svn-client package.
  • If you have neither Fink or MacPorts you can grab subversion from Martin Ott’s homepage or any of the pre-build binaries from here.

5.7.2 Setting LC_CTYPE

You must set the LC_CTYPE variable to use UTF-8. If you do not, svn will give you an svn: Can't recode string error when it stumbles upon non-ASCII filenames (some of the bundle items use these).

If you are using bash you should put this in your ~/.bash_profile (or a similar file which gets sourced when you open a terminal):

export LC_CTYPE=en_US.UTF-8 

Users of zsh should put it in ~/.zshrc and tcsh users should instead put this line in their ~/.tcshrc:

setenv LC_CTYPE en_US.UTF-8 

Remember that after adding this, you need to start a new shell for the updated profile to take effect.

Also be aware that the LC_ALL environment variable takes precedence over LC_CTYPE, so if you have set this elsewhere you should either unset it or change that to use UTF-8.

5.7.3 Installing a Bundle

When you have svn installed it is relatively easy to either checkout or export a bundle. TextMate searches for bundles in all the usual library locations, so if you have the rights to do so (on your machine) it is recommended that you perform all checkouts to /Library instead of ~/Library, since this then keeps installed bundles separate from custom bundles (or bundles you have edited).

As an example, to install the Haskell bundle, first create the install directory, then change to it and ask svn to check it out:

mkdir -p /Library/Application\ Support/TextMate/Bundles cd /Library/Application\ Support/TextMate/Bundles svn co 

At a later time you can update the bundles which you have installed by executing these two lines:

cd /Library/Application\ Support/TextMate/Bundles svn up *.tmbundle 

If TextMate is running while you perform the update, you may want to also execute the following line:

osascript -e 'tell app "TextMate" to reload bundles' 

This is equivalent to selecting Bundles → Bundle Editor → Reload Bundles from within TextMate.

5.7.4 Support Folder

Included with TextMate is a support folder which contains miscellaneous support items used by various bundle items. This folder is reachable via the TM_SUPPORT_PATH environment variable and would normally point to /Applications/

If you checkout a bundle from the subversion repository then this bundle may rely on a newer version of the support folder than the one included with TextMate. If this is the case, you will need to also checkout a local copy of the support folder.

The process is similar to checking out a bundle, first ensure you have LC_CTYPE setup properly and then execute the following in your shell:

cd /Library/Application\ Support/TextMate svn co 

After this you can test it by pasting the following line into TextMate and pressing ⌃R (to execute it):


It should result in the following output:

/Library/Application Support/TextMate/Support 

The support folder contains a version file (named version) so rather than pick the most local version of the support folder, TextMate will choose the one with the highest version. This means that if you do checkout a local copy of the support folder and later update TextMate, your local (potentially outdated) copy will not eclipse the default one.

5.7.5 RSS Feed With Bundle Change Log

Changes made to bundles are not part of the normal release notes. Instead these are available through an RSS feed.

6 Macros

TextMate supports recordable macros. A macro is recorded by selecting Macros → Start Recording from the Bundles menu.

While recording, a red dot will pulsate in the right part of status bar and all text editing actions are recorded together with things like Find, running commands, inserting snippets etc. When done, you select Stop Recording and can either replay the recorded macro or save it for later use.

When saving a macro, it will appear in the bundle editor as (currently) a read-only macro which can get an activation sequence and scope selector, just like any other bundle item.

It is possible to set whether or not the macro should use a local clipboard while being executed. The local clipboard is generally advantageous (thus the default) but sometimes you may want the macro to affect the “real” clipboard and can disable this option.

7 Snippets

A snippet is a piece of text that you would like to insert in your document. It can include code to run at insertion time, variables (like selected text), tab stops/placeholders for missing information (which you can tab through after insertion) and perform transformations on the data which you enter in the placeholders.

Snippet Editor

7.1 Plain Text

In the simplest case, you can use snippets to insert text that you do not want to type again and again, either because you type it a lot, or because the actual text to insert is hard to remember (like your bank account details or the HTML entities for the Apple modifier keys).

If you use snippets to insert plain text there is only one thing you should be aware of: $ and ` are reserved characters. So if you want to insert one of these, prefix it with an escape (i.e. \$). An escape not followed by one of these two characters (or followed by another escape) will be inserted as a literal character.

7.2 Variables

You can insert the value of a variable by prefixing the name of the variable with $. All the normal dynamic variables are supported, the most useful probably being TM_SELECTED_TEXT. If for example we want to create a snippet which wraps the selection in a LaTeX \textbf command, we can make a snippet which is:


If no text is selected the variable will not be set, so nothing will be inserted in its place. We can provide a default value by using this syntax: ${«variable»:«default value»}. For example:

\textbf{${TM_SELECTED_TEXT:no text was selected}} 

The default value can itself contain variables or shell code. If you want the default text to contain a }, you need to escape it. But all other characters are used verbatim.

Variables also support regular expression replacements using this syntax: ${«variable»/«regexp»/«format»/«options»}. If the variable is not set the replacement will be performed on the empty string. For example, to prepend a bullet to each non-empty line in the selection (and insert that) we can do:

${TM_SELECTED_TEXT/^.+$/• $0/g} 

7.3 Interpolated Shell Code

You can use backticks to have shell code executed when the snippet is inserted. The result from running the code gets inserted into the snippet, though with the last newline in the result removed (if present). So for example to create a snippet that wraps the selection in an HTML link, where the URL of that link comes from the clipboard, we can do:

<a href="`pbpaste`.html">$TM_SELECTED_TEXT</a> 

Since this is normal bash code, we can write a small program. For example we can let it verify that the clipboard contains only a single line of text like this:

<a href="` if [[ $(pbpaste|wc -l) -eq 0 ]] then pbpaste else echo fi `">$TM_SELECTED_TEXT</a> 

Inside shell code, the only character you need to escape is the backtick.

7.4 Tab Stops

After insertion, the caret will be placed after the last character of the snippet. This is not always desirable and we can change that by using $0 to mark where we want the caret to be. So if for example we make an HTML div-snippet and want the caret to end between the opening and closing tags, we could make it like this:

<div> $0 </div> 

Often though we want to fill in text in several places in the snippet. Multiple tab stops can be provided by inserting $1$n. The caret will start at $1, then when pressing tab it will move to $2 and $3 on next tab etc. until there are no more tab stops. If you do not explicitly set $0, the caret will be at the end of the snippet.

So we could for example change the above to:

<div$1> $0 </div> 

This allows us to fill in an argument and then tab on to $0.

7.5 Placeholders

Like variables, tab stops can also have default values (and are generally referred to as placeholders when they do). The syntax is the same: ${«tab stop»:«default value»}. And the default value can contain both text, shell code and other placeholders. So we can refine the previous example further:

<div${1: id="${2:some_id}"}> $0 </div> 

Inserting this snippet will insert a div tag with the id argument selected and we can then decide either to overtype the argument (i.e. delete it) and press tab again to reach $0, or we can press tab immediately to get to the second tab stop (the value part of the argument) and edit that.

When you edit the placeholder text, any embedded tab stops will be removed.

7.6 Mirrors

There are times when you need to provide the same value several places in the inserted text and in these situations you can re-use the tab stop to signal that you want it mirrored at that location. So for example to create a LaTeX environment with a snippet, we can use:

\begin{${1:enumerate}} $0 \end{$1} 

After inserting this snippet, enumerate will be selected and if we edit it, the changes will be reflected in the \end part as well.

7.7 Transformations

There are situations where we want our placeholder text mirrored but with slight changes or where we want some text to appear depending on the value/presence of a placeholder.

We can accomplish this by doing a regular expression substitution on the placeholder text (when mirroring it). The syntax for this is: ${«tab stop»/«regexp»/«format»/«options»}.

As an example, the Objective-C getter/setter methods (prior to the @property keyword) often look like this (in the thread-unsafe form):

- (id)foo { return foo; } - (void)setFoo:(id)aValue { [foo autorelease]; foo = [aValue retain]; } 

In the format string we can use \u to uppercase the next character, so a snippet that only asks for the name of the instance variable once could look like this:

- (${1:id})${2:foo} { return $2; } - (void)set${2/./\u$0/}:($1)aValue { [$2 autorelease]; $2 = [aValue retain]; } 

We can also use conditional insertions in the format string to make decisions. For example if we create a snippet for a method we can let the return type decide whether or not the method should include a return statement like this:

- (${1:void})${2:methodName} {${1/void$|(.+)/(?1:\n\treturn nil;)/} } 

Here we match placeholder 1 against void or anything (.+) and put the latter match in capture register 1. Then only if we did match something (other than void) will we insert a newline, tab and the return nil; text.

8 Shell Commands

The shell is a scripting language used to piece together various programs (shell commands), and often in an interactive way, e.g. as done when launching Terminal and entering commands to execute.

For a thorough introduction to the shell scripting language have a look at this shell tutorial provided by Apple.

8.1 Executing Commands / Filtering Text

TextMate allows shell commands to be executed in different contexts. Some of the more useful options are:

  1. In the current document, either press ⌃R with no selection to run the current line as a shell command, or select one or more lines and use ⌃R to run the selection as a shell script (it supports shebang as well).

    Execute Line

  2. From the Text menu you can select Filter Through Command… (⌥⌘R) which opens a panel where you can enter a shell command to run and set what should be given as input (stdin) plus what to do with the output of the command (often you want to set input to the selected text and let the output replace the selection).

    Filter Through Command

  3. Commands via the Bundle Editor. The first two options are mostly for one-shot commands, whereas commands created in the Bundle Editor are for stuff you want to run again later. The options here are the same as those of option 2, i.e. you can set what to do with input/output, even have the output shown as a tool tip (e.g. for commands which lookup help for the current word) or HTML (e.g. for commands which build the project and show results, incrementally). You can also set that documents should be saved before executing the command and give the command a key equivalent or tab trigger.

    Command Editor

8.2 Search Path

When running a command from Terminal, the shell will use the value of the PATH variable to locate it (when it is specified without an absolute location). For example ruby is located in /usr/bin/ruby and svn is (for me) located in /opt/local/bin/svn.

TextMate inherits the value of PATH from Finder, which has only a few search locations specified, so for many users, it is necessary to augment this PATH if they need TextMate to find git, pdflatex, or similar commands not included with Mac OS X.

There are two ways to setup PATH for TextMate. Either via Preferences → Advanced → Shell Variables or by editing ~/.MacOSX/environment.plist.

The former is by far the simplest, the latter is a property list with environment variables read by Finder when you login, so values set here should affect all applications.

9 Environment Variables

Environment variables are used extensively in TextMate to provide scripts and commands with information.

Here is how to read the value of a variable (named VAR) in different scripting languages:

  • Bash — "$VAR"
  • Perl — $ENV{'VAR'}
  • PHP — $_ENV['VAR']
  • Python — os.environ['VAR'] (remember to import os first)
  • Ruby — ENV['VAR']

You can use them directly in Snippets, like in bash. Both bash and snippets support an extended form (${VAR}) where it is possible to do replacements in the variable, provide fallback values (if it is unset) etc.

Remember to double-quote variables used in shell scripts, otherwise bash will first expand the variable to its value and then split this according to the input-field-separator characters (read as the IFS variable, defaults to spaces, tabs and newlines). This means if TM_FILENAME is My Document.txt and we execute rm $TM_FILENAME then rm will actually get two arguments, first one being My and the second one being Document.txt.

For info about what can be done with environment variables in bash, see this blog post about the issue or check out the bash man file.

9.1 Dynamic Variables

The following variables reflect the users current configuration, which file he has open, where the caret is located in that file, the selection in the project drawer and so on.

A script can read these variables and make decisions accordingly.

Some of the variables are not always present. For example if the current file is untitled, or there is no selection, the corresponding variable will be unset. This is useful for example to make a command work with the selection, but fall back on the current line or word.

Bash has shorthand notation for providing a default value when a variable is not set, for example to fallback on the current word when there is no selection, we would use: "${TM_SELECTED_TEXT:-$TM_CURRENT_WORD}".

  • TM_BUNDLE_SUPPORT — shell commands which are (indirectly) triggered from a bundle item (which could be a Command, Drag Command, Macro, or Snippet) will have this variable pointing to the Support folder of the bundle that ran the item, if such a folder exists. In addition, $TM_BUNDLE_SUPPORT/bin will be added to the path.
  • TM_CURRENT_LINE — textual content of the current line.
  • TM_CURRENT_WORD — the word in which the caret is located.
  • TM_DIRECTORY — the folder of the current document (may not be set).
  • TM_FILEPATH — path (including file name) for the current document (may not be set).
  • TM_LINE_INDEX — the index in the current line which marks the caret’s location. This index is zero-based and takes the utf-8 encoding of the line (e.g. read as TM_CURRENT_LINE) into account. So to split a line into what is to the left and right of the caret you could do:
    echo "Left: »${TM_CURRENT_LINE:0:TM_LINE_INDEX}«" echo "Right: »${TM_CURRENT_LINE:TM_LINE_INDEX}«" 
  • TM_LINE_NUMBER — the carets line position (counting from 1). For example if you need to work with the part of the document above the caret you can set the commands input to “Entire Document” and use the following to cut off the part below and including the current line:
    head -n$((TM_LINE_NUMBER-1)) 
  • TM_PROJECT_DIRECTORY — the top-level folder in the project drawer (may not be set).
  • TM_SCOPE — the scope that the caret is inside. See scope selectors for information about scopes.
  • TM_SELECTED_FILES — space separated list of the files and folders selected in the project drawer (may not be set). The paths are shell-escaped, so to use these, you need to prefix the line with eval (to make the shell re-evaluate the line, after expanding the variable). For example to run the file command on all selected files in the project drawer, the shell command would be:
    eval file "$TM_SELECTED_FILES" 

    It is also possible to convert it to an (bash) array and iterate over this, for example:

    eval arr=("$TM_SELECTED_FILES") for (( i = 0; i < ${#arr[@]}; i++ )); do file "${arr[$i]}" done 
  • TM_SELECTED_FILE — full path of the first selected file or folder in the project drawer (may not be set).
  • TM_SELECTED_TEXT — full content of the selection (may not be set). Note that environment variables have a size limitation of roughly 64 KB, so if the user selects more than that, this variable will not reflect the actual selection (commands that need to work with the selection should generally set this to be the standard input).
  • TM_SOFT_TABS — this will have the value YES if the user has enabled soft tabs, otherwise it has the value NO. This is useful when a shell command generates an indented result and wants to match the users preferences with respect to tabs versus spaces for the indent.
  • TM_SUPPORT_PATH — the TextMate application bundle contains a support folder with several items which are used by some of the default commands (for example CocoaDialog, Markdown, the SCM commit window, Textile, tidy, etc.). This variable points to that support folder. Generally you would not need to use the variable directly since $TM_SUPPORT_PATH/bin is added to the path, so using some of the bundled commands can be done without having to specify their full path.
  • TM_TAB_SIZE — the tab size as shown in the status bar. This is useful when creating commands which need to present the current document in another form (Tidy, convert to HTML or similar) or generate a result which needs to match the tab size of the document. See also TM_SOFT_TABS.

9.2 Static Variables

In addition to the dynamic variables, which TextMate provides automatically, it is sometimes useful to provide a list of static variables.

For example you may have templates or snippets that should insert your company name and prefer not to put the value directly in these, or there could be shared commands which need localized settings, for example the SQL bundle has a query command which use variables for username, password and database.

For this reason it is possible to set a default list of environment variables in Preferences → Advanced → Shell Variables.

Shell Variables

These variables are given to all shell commands started from TextMate and can also be used in snippets (as can the dynamic variables for that matter).

9.3 Context Dependent Variables

Some variables are a cross between dynamic and static. For example the Source bundle contains a Toggle Comment command which will toggle the comment for the current line or selection. This command uses three variables to decide what type of comment style the user wants.

A user who works with multiple languages will however need to specify this per language. This can be done by setting the shellVariables array in the bundle preferences and provide the proper scope selector to limit these variables.

Scoped Environment Variables

This has the advantage of actually being based on the carets location, which for the Toggle Comment command allows us to have it work differently for JavaScript, CSS, HTML and embedded PHP + Ruby, all in the same document.

An example of setting the 3 variables to comment the entire block (instead of line-by-line) with the HTML/SGML/XML comment markers is shown here:

shellVariables = ( { name = 'TM_COMMENT_START'; value = '<!-- '; }, { name = 'TM_COMMENT_END'; value = ' -->'; }, { name = 'TM_COMMENT_MODE'; value = 'block'; }, ); 

9.4 Project Dependent Variables

Sometimes it is useful to have a command customized differently depending on the project. For this reason, it is possible to set variables for individual projects.

The way to do this is currently a little secret but if you deselect everything in the project drawer, then click the info (circled I) button, a panel will appear where you can set variables.

These variables are saved in the project file (*.tmproj) and will exist only for snippets and (shell) commands executed in the context of that project.

10 Commands

Commands are scripts interpreted by bash or the interpreter specified at the top using shebang notation (e.g. #!/usr/bin/ruby).

Editing commands is done from the Bundle Editor which you can open by selecting Bundles → Bundle Editor → Edit Commands…

Command Editor

TextMate can save either the current document or all modified documents in the project, before running the command. This is set using the top pop-up control. A document will only be saved when it has been modified.

10.1 Command Input

When running a command the various environment variables will be available for the command to read and use. In addition, the command can read either the entire document or the selected text as input (stdin).

If the input is set to “Selected Text” and there is no selection, the command will instead get the fallback unit specified in the additional input pop-up control. If the fallback unit is used and the output is set to “Replace Selection” then the unit used as input will be replaced. So if we make a command like tr '[a-z]' '[A-Z]' (uppercase text) and set input to Selected Text but fallback to word and set output to replace selected text, then running the command with no selection, will uppercase the current word.

Input Fallback Options

One fallback unit which requires a little explanation is Scope. When the input is set to this, TextMate will search backwards and forwards for the first character which is not matched by the scope selector of the command and use those as boundaries for the input.

This means that if the language grammar marks up URLs and gives these a scope of markup.underline.url then a command with that as the scope selector can set its input to Selection or Scope and will thus get the URL as input, when this command is executed with the caret on an URL.

When a command name is shown outside the bundle editor (like in the menus) and a fallback unit is provided then TextMate will substitute “Unit / Selection” (in its name) with either “Unit” or “Selection” depending on whether or not text is selected. The text used for Unit should be a single word representing the fallback unit, i.e. Character, Word, Line, Scope (or what the scope represents, but as a single word), or Document. So if you make a command with the name “Encrypt Document / Selection” and specify its input as Selected Text, but with Document set as a fallback, this command will be presented as “Encrypt Document” when no text is selected, otherwise “Encrypt Selection.”

10.2 Command Output

TextMate can do miscellaneous things with the output (stdout) of a command, the options are:

  • Replace Selected Text / Document — this output option is mainly for commands which transform the selection/document, for example running the document through tidy or sort the lines read from stdin.
  • Insert as Text / Snippet — commands which generate output to be inserted in the document, for example inserting missing close tag (by parsing the document read from stdin down to the caret position) or similar.
  • Show as Tool Tip — commands which are mainly actions, like submit the selection to a pasting service or similar can discretely report the status of the action using just a tool tip.

    Tool Tip Output

  • Show as HTML — this output option simply shows the output as HTML, but has some additional advantages mentioned in next section. It is especially useful for commands which need to report incremental progress, as shown with the Xcode Build below.

    Build With Xcode

  • Create New Document — with some transformations (like converting a Markdown document to HTML) it may be preferable to open the result in a new document rather than overwrite the existing document and that is what this option is for. There are also commands for which the result is best shown as a document, for example the output from diff can be shown as a (new) document to get nice syntax coloring.

    Diff Result

10.3 HTML Output

The HTML output option has a few advantages in addition to providing access to WebKit’s HTML and CSS engine.

  1. The HTML output does not stall TextMate while the command is running. A progress indicator is shown in the upper right hand corner while the command is running and it can be aborted by closing the output window (a confirmation requester is presented).

    Html Output Progress Indicator

  2. JavaScript running as part of the output has access to a TextMate object with a system method that mimics the one provided to Dashboard widgets. The TextMate object also has an isBusy property which can be set to true or false to control the windows progress indicator. So in the simplest case, to allow the user to start/stop the progress indicator one could make a command like this:
    cat <<'EOF' <a href="javascript:TextMate.isBusy = true">Start</a> <a href="javascript:TextMate.isBusy = false">Stop</a> EOF 

    To create a link which opens the user’s browser, one could use the system method like this:

    cat <<'EOF' <a href="javascript:TextMate.system( 'open', null);">Open Link</a> EOF 

    The system method allows starting (and stopping) of commands asynchronously, reading standard out/error from the command and sending data to the commands standard input. For further information see the Dashboard documentation.

  3. The HTML output allows the use of the TextMate URL scheme to link back to a given document. This is useful either when the command reports errors (or warnings) with the current document (e.g. a build command or a validator) or when the command refers to other files in the project, e.g. svn status.
  4. Using either Tiger or Schuberts PDF Browser Plug-in it is possible to have the HTML output show PDF files. Mainly this is useful for typesetting programs like LaTeX, where it is then possible to typeset and view the result without leaving TextMate.
  5. It is possible to redirect to other pages and thereby treat the HTML output as a shortcut to your browser. For example in PHP the “Documentation for Word” command outputs a line like this:
    echo "<meta http-equiv='Refresh' content='0;URL=$TM_CURRENT_WORD'>" 

Due to a (presumed) security restriction with WebKit it is not possible to have the HTML output redirect, link or reference files on your disk via the file: URL scheme. Instead you can use the tm-file: URL scheme, which works exactly like file:, but does not have this cross-scheme restriction.

For a longer post about how the HTML output can be used visit the TextMate blog.

10.4 Changing Output Type

There are situations where it is useful to change the output option of a command from within the command. For example a command which looks up documentation for the current word may want to show a “no documentation found” tool tip for when there is no documentation, but otherwise use the HTML output option for the result.

Command Output Options

TextMate has a few predefined bash functions which can be used for this purpose. They optionally take a string as an argument which is first echo’ed to stdout.

These functions only work when the initial output option is not set as “Show as HTML”. The list of functions is as follows:

  • exit_discard
  • exit_replace_text
  • exit_replace_document
  • exit_insert_text
  • exit_insert_snippet
  • exit_show_html
  • exit_show_tool_tip
  • exit_create_new_document

So for example the Diff bundle has a “[Diff] Document With Saved Copy” that compares the current document with the version saved on disk. The default output option for that is to create a new document (showing the diff output with syntax highlighting), but it will show an error (as a tool tip) if there is no file on disk. This can be done using the following command:

if [[ -e "$TM_FILEPATH" ]] # does the file exist? then diff -u "$TM_FILEPATH" - else exit_show_tool_tip "No saved copy exists." fi 

10.5 Useful bash Functions

When running commands there are a few predefined bash functions which might be useful:

  • require_cmd — ensure that the command given as the first argument exists in the path and otherwise report an error to the user and abort the command. This is useful if you rely on commands not shipped with OS X and want to distribute your work, for example the Subversion commands start by doing:
    require_cmd svn 
  • rescan_project — currently TextMate will only update the project drawer (and reload the current file if it was changed externally) when regaining focus. This bash function is shorthand for using AppleScript to deactivate and reactivate TextMate. It is useful if your command either modifies the current document (on disk) or changes files in folders which are part of the current project.
  • pre — this command reads text from stdin and outputs an HTML-escaped version to stdout, putting the entire thing in <pre>…</pre> (though with word wrap enabled) and converting <, > and & to the corresponding HTML entities. This is useful when you want to show raw output but use the HTML output option. In the simplest case you can just specify pre as the command and set input to “Entire Document” and output to “Show as HTML”, but generally you would probably want the result from some command to be piped through pre, for example:
    make clean|pre 

The functions mentioned above are all defined in $TM_SUPPORT_PATH/lib/ There are also functions to aid in HTML construction (from bash) in $TM_SUPPORT_PATH/lib/, but this file is not sourced by default. So to use the functions defined in that file you would start by sourcing it e.g.:

. "$TM_SUPPORT_PATH/lib/" redirect "" 

10.6 Dialogs (Requesting Input & Showing Progress)

TextMate ships with CocoaDialog so this can be used out-of-the-box. You call CocoaDialog (follow the link for full documentation) with the type of dialog you want and it will return two lines of text, the first is the button pressed (as a number) and the second is the actual result. While a little cumbersome, here is an example of how to request a line of text and only proceed if the user did not cancel:

res=$(CocoaDialog inputbox --title "I Need Input" \ --informative-text "Please give me a string:" \ --button1 "Okay" --button2 "Cancel") [[ $(head -n1 <<<"$res") == "2" ]] && exit_discard res=$(tail -n1 <<<"$res") echo "You entered: $res" 

We first call CocoaDialog to get a string of text. Then we test if the first line returned (using head) is equal to 2, which corresponds to the Cancel button and if so, we exit (using the discard output option). We then go on to extract the last line of the result and echo that.

Cocoadialog Inputbox

Another common dialog type is the progress indicator. The determinate version reads from stdin the value and text to use for each step. This means we can simply pipe that info to CocoaDialog in each step of our command, a simple example could be:

for (( i = 1; i <= 100; i++ )); do echo "$i We're now at $i%"; sleep .05 done|CocoaDialog progressbar --title "My Program" 

Cocoadialog Determinate Progress

Often though we want to show the indeterminate version. This dialog stays onscreen for as long as its stdin is open. This means we can use a pipe like above but if we want a result back from the command that we are executing, we can instead redirect the commands stderr to an instance of CocoaDialog (using process substitution), this is shown in the following example:

revs=$(svn log -q "$TM_FILEPATH"|grep -v '^-*$' \ 2> >(CocoaDialog progressbar --indeterminate \ --title "View Revision…" \ --text "Retrieving List of Revisions…" \ )) echo "$revs" 

Cocoadialog Indeterminate Progress

CocoaDialog also has other dialog types, like a pop-up list, file panel, text box and so on, but as an alternative there is also AppleScript.

If you open Script Editor and then open the Standard Additions dictionary (via Open Dictionary…) there are commands under User Interaction which allow various dialogs. One caveat though, in current version (1.5) TextMate will not listen to AppleScript commands while executing shell commands with an output option other than Show as HTML. This means that instead of targeting TextMate, you should use SystemUIServer or similar and in addition to that, since SystemUIServer needs to be activated to show the dialog (with focus) you need to reactivate TextMate. Here is an example of a command that allows selecting an item from a list:

res=$(osascript <<'AS' tell app "TextMate" activate choose from list { "red", "green", "blue" } \ with title "Pick a Color" \ with prompt "What color do you like?" end tell AS) echo "You selected: $res" osascript -e 'tell app "TextMate" to activate' &>/dev/null & 

The first part is just a small AppleScript which is executed from shell via osascript (reading the script from stdin using a here-doc). The last part is the line that gives focus back to TextMate but because TextMate will not respond to this event before the shell command has completed its execution, we need to run it asynchronously, which is done by adding & to the end of the command. The &>/dev/null part is to detach stdout/error from the shell command so that this does not cause a stall.

AppleScript Choose From List

11 Drag Commands

Drag commands are like normal commands but they are activated by dropping a particular file type (specified as a list of file type extensions) into the editing window.

Drag Command File Types

The output from executing a drag command is always inserted as a snippet and the drag command has three (additional) environment variables available:

  • TM_DROPPED_FILE — relative path of the file dropped (relative to the document directory, which is also set as the current directory).
  • TM_DROPPED_FILEPATH — the absolute path of the file dropped.
  • TM_MODIFIER_FLAGS — the modifier keys which were held down when the file got dropped. This is a bitwise OR in the form: SHIFT|CONTROL|OPTION|COMMAND (in case all modifiers were down).

So here is a slightly complex drag command:

img="$TM_DROPPED_FILE" echo -n "<img src=\"$img\" " sips -g pixelWidth -g pixelHeight "$img" \ |awk '/pixelWidth/ { printf("width=\"%d\" ", $2) } /pixelHeight/ { printf("height=\"%d\" ", $2) }' base=${img##*/} alt=$(tr <<<${base%.*} '[_-]' ' '|perl -pe 's/(\w+)/\u$1/g') echo -n "alt=\"\${1:$alt}\">" 

First we output the <img src="…" part. Then we use sips to query the image and awk to parse the output from sips and output the proper width="…" and height="…" arguments. Last we convert - and _ in the path to spaces and capitalize each word and output this as the final alt="…" argument, where we make this text a placeholder (since the entire thing is inserted as a snippet).

Drag Command Result

12 Language Grammars

Language grammars are used to assign names to document elements such as keywords, comments, strings or similar. The purpose of this is to allow styling (syntax highlighting) and to make the text editor “smart” about which context the caret is in. For example you may want a key stroke or tab trigger to act differently depending on the context, or you may want to disable spell check as you type those portions of your text document which are not prose (e.g. HTML tags).

The language grammar is used only to parse the document and assign names to subsets of this document. Then scope selectors can be used for styling, preferences and deciding how keys and tab triggers should expand.

For a more thorough introduction to this concept see the introduction to scopes blog post.

12.1 Example Grammar

You can create a new language grammar by opening the bundle editor (Window → Show Bundle Editor) and select “New Language” from the add button in the lower left corner.

This will give you a starting grammar which will look like the one below, so let us start by explaining that.

 1 { scopeName = 'source.untitled'; 2 fileTypes = ( ); 3 foldingStartMarker = '\{\s*$'; 4 foldingStopMarker = '^\s*\}'; 5 patterns = ( 6 { name = 'keyword.control.untitled'; 7 match = '\b(if|while|for|return)\b'; 8 }, 9 { name = 'string.quoted.double.untitled'; 10 begin = '"'; 11 end = '"'; 12 patterns = ( 13 { name = 'constant.character.escape.untitled'; 14 match = '\\.'; 15 } 16 ); 17 }, 18 ); 19 } 

The format is the property list format and at the root level there are five key/value pairs:

  • scopeName (line 1) — this should be a unique name for the grammar, following the convention of being a dot-separated name where each new (left-most) part specializes the name. Normally it would be a two-part name where the first is either text or source and the second is the name of the language or document type. But if you are specializing an existing type, you probably want to derive the name from the type you are specializing. For example Markdown is text.html.markdown and Ruby on Rails (rhtml files) is text.html.rails. The advantage of deriving it from (in this case) text.html is that everything which works in the text.html scope will also work in the text.html.«something» scope (but with a lower precedence than something specifically targeting text.html.«something»).
  • fileTypes (line 2) — this is an array of file type extensions that the grammar should (by default) be used with. This is referenced when TextMate does not know what grammar to use for a file the user opens. If however the user selects a grammar from the language pop-up in the status bar, TextMate will remember that choice.
  • foldingStartMarker / foldingStopMarker (line 3-4) — these are regular expressions that lines (in the document) are matched against. If a line matches one of the patterns (but not both), it becomes a folding marker (see the foldings section for more info).
  • patterns (line 5-18) — this is an array with the actual rules used to parse the document. In this example there are two rules (line 6-8 and 9-17). Rules will be explained in the next section.

There are two additional (root level) keys which are not used in the example:

  • firstLineMatch — a regular expression which is matched against the first line of the document (when it is first loaded). If it matches, the grammar is used for the document (unless there is a user override). Example: ^#!/.*\bruby\b.
  • repository — a dictionary (i.e. key/value pairs) of rules which can be included from other places in the grammar. The key is the name of the rule and the value is the actual rule. Further explanation (and example) follow with the description of the include rule key.

12.2 Language Rules

A language rule is responsible for matching a portion of the document. Generally a rule will specify a name which gets assigned to the part of the document which is matched by that rule.

There are two ways a rule can match the document. It can either provide a single regular expression, or two. As with the match key in the first rule above (lines 6-8), everything which matches that regular expression will then get the name specified by that rule. For example the first rule above assigns the name keyword.control.untitled to the following keywords: if, while, for and return. We can then use a scope selector of keyword.control to have our theme style these keywords.

The other type of match is the one used by the second rule (lines 9-17). Here two regular expressions are given using the begin and end keys. The name of the rule will be assigned from where the begin pattern matches to where the end pattern matches (including both matches). If there is no match for the end pattern, the end of the document is used.

In this latter form, the rule can have sub-rules which are matched against the part between the begin and end matches. In our example here we match strings that start and end with a quote character and escape characters are marked up as constant.character.escape.untitled inside the matched strings (line 13-15).

Note that the regular expressions are matched against only a single line of the document at a time. That means it is not possible to use a pattern that matches multiple lines. The reason for this is technical: being able to restart the parser at an arbitrary line and having to re-parse only the minimal number of lines affected by an edit. In most situations it is possible to use the begin/end model to overcome this limitation.

12.3 Rule Keys

What follows is a list of all keys which can be used in a rule.

  • name — the name which gets assigned to the portion matched. This is used for styling and scope-specific settings and actions, which means it should generally be derived from one of the standard names (see naming conventions later).
  • match — a regular expression which is used to identify the portion of text to which the name should be assigned. Example: '\b(true|false)\b'.
  • begin, end — these keys allow matches which span several lines and must both be mutually exclusive with the match key. Each is a regular expression pattern. begin is the pattern that starts the block and end is the pattern which ends the block. Captures from the begin pattern can be referenced in the end pattern by using normal regular expression back-references. This is often used with here-docs, for example:
    { name = ''; begin = '<<(\w+)'; // match here-doc token end = '^\1$'; // match end of here-doc } 

    A begin/end rule can have nested patterns using the patterns key. For example we can do:

    { begin = '<%'; end = '%>'; patterns = ( { match = '\b(def|end)\b'; … }, … ); }; 

    The above will match def and end keywords inside a <% … %> block (though for embedded languages see info about the include key later).

  • contentName — this key is similar to the name key but only assigns the name to the text between what is matched by the begin/end patterns. For example to get the text between #if 0 and #endif marked up as a comment, we would do:
    { begin = '#if 0(\s.*)?$'; end = '#endif'; contentName = 'comment.block.preprocessor'; }; 
  • captures, beginCaptures, endCaptures — these keys allow you to assign attributes to the captures of the match, begin, or end patterns. Using the captures key for a begin/end rule is short-hand for giving both beginCaptures and endCaptures with same values.

    The value of these keys is a dictionary with the key being the capture number and the value being a dictionary of attributes to assign to the captured text. Currently name is the only attribute supported. Here is an example:

    { match = '(@selector\()(.*?)(\))'; captures = { 1 = { name = 'storage.type.objc'; }; 3 = { name = 'storage.type.objc'; }; }; }; 

    In that example we match text like @selector(windowWillClose:) but the storage.type.objc name will only be assigned to @selector( and ).

  • include — this allows you to reference a different language, recursively reference the grammar itself or a rule declared in this file’s repository.
    1. To reference another language, use the scope name of that language:
      { begin = '<\?(php|=)?'; end = '\?>'; patterns = ( { include = "source.php"; } ); } 
    2. To reference the grammar itself, use $self:
      { begin = '\('; end = '\)'; patterns = ( { include = "$self"; } ); } 
    3. To reference a rule from the current grammars repository, prefix the name with a pound sign (#):
      patterns = ( { begin = '"'; end = '"'; patterns = ( { include = "#escaped-char"; }, { include = "#variable"; } ); }, … ); // end of patterns repository = { escaped-char = { match = '\\.'; }; variable = { match = '\$[a-zA-Z0-9_]+'; }; }; 

      This can also be used to match recursive constructs like balanced characters:

      patterns = ( { name = 'string.unquoted.qq.perl'; begin = 'qq\('; end = '\)'; patterns = ( { include = '#qq_string_content'; }, ); }, … ); // end of patterns repository = { qq_string_content = { begin = '\('; end = '\)'; patterns = ( { include = '#qq_string_content'; }, ); }; }; 

      This will correctly match a string like: qq( this (is (the) entire) string).

12.4 Naming Conventions

TextMate is free-form in the sense that you can assign basically any name you wish to any part of the document that you can markup with the grammar system and then use that name in scope selectors.

There are however conventions so that one theme can target as many languages as possible, without having dozens of rules specific to each language and also so that functionality (mainly preferences) can be re-used across languages, e.g. you probably do not want an apostrophe to be auto-paired when inserted in strings and comments, regardless of the language you are in, so it makes sense to only set this up once.

Before going through the conventions, here are a few things to keep in mind:

  1. A minimal theme will only assign styles to 10 of the 11 root groups below (meta does not get a visual style), so you should “spread out” your naming i.e. instead of putting everything below keyword (as your formal language definition may insist) you should think “would I want these two elements styled differently?” and if so, they should probably be put into different root groups.
  2. Even though you should “spread out” your names, when you have found the group in which you want to place your element (e.g. storage) you should re-use the existing names used below that group (for storage that is modifier or type) rather than make up a new sub-type. You should however append as much information to the sub-type you choose. For example if you are matching the static storage modifier, then instead of just naming it storage.modifier use storage.modifier.static.«language». A scope selector of just storage.modifier will match both, but having the extra information in the name means it is possible to specifically target it disregarding the other storage modifiers.
  3. Put the language name last in the name. This may seem redundant, since you can generally use a scope selector of: source.«language» storage.modifier, but when embedding languages, this is not always possible.

And now the 11 root groups which are currently in use with some explanation about their intended purpose. This is presented as a hierarchical list but the actual scope name is obtained by joining the name from each level with a dot. For example double-slash is comment.line.double-slash.

  • comment — for comments.
    • line— line comments, we specialize further so that the type of comment start character(s) can be extracted from the scope.
      • double-slash// comment
      • double-dash-- comment
      • number-sign# comment
      • percentage% comment
      • character — other types of line comments.
    • block — multi-line comments like /* … */ and <!-- … -->.
      • documentation — embedded documentation.
  • constant — various forms of constants.
    • numeric — those which represent numbers, e.g. 42, 1.3f, 0x4AB1U.
    • character — those which represent characters, e.g. &lt;, \e, \031.
      • escape — escape sequences like \e would be constant.character.escape.
    • language — constants (generally) provided by the language which are “special” like true, false, nil, YES, NO, etc.
    • other — other constants, e.g. colors in CSS.
  • entity — an entity refers to a larger part of the document, for example a chapter, class, function, or tag. We do not scope the entire entity as entity.* (we use meta.* for that). But we do use entity.* for the “placeholders” in the larger entity, e.g. if the entity is a chapter, we would use for the chapter title.
    • name— we are naming the larger entity.
      • function — the name of a function.
      • type — the name of a type declaration or class.
      • tag — a tag name.
      • section — the name is the name of a section/heading.
    • other— other entities.
      • inherited-class — the superclass/baseclass name.
      • attribute-name — the name of an attribute (mainly in tags).
  • invalid — stuff which is “invalid”.
    • illegal — illegal, e.g. an ampersand or lower-than character in HTML (which is not part of an entity/tag).
    • deprecated — for deprecated stuff e.g. using an API function which is deprecated or using styling with strict HTML.
  • keyword — keywords (when these do not fall into the other groups).
    • control — mainly related to flow control like continue, while, return, etc.
    • operator — operators can either be textual (e.g. or) or be characters.
    • other — other keywords.
  • markup — this is for markup languages and generally applies to larger subsets of the text.
    • underline— underlined text.
      • link — this is for links, as a convenience this is derived from markup.underline so that if there is no theme rule which specifically targets then it will inherit the underline style.
    • bold — bold text (text which is strong and similar should preferably be derived from this name).
    • heading — a section header. Optionally provide the heading level as the next element, for example markup.heading.2.html for <h2>…</h2> in HTML.
    • italic — italic text (text which is emphasized and similar should preferably be derived from this name).
    • list— list items.
      • numbered — numbered list items.
      • unnumbered — unnumbered list items.
    • quote — quoted (sometimes block quoted) text.
    • raw — text which is verbatim, e.g. code listings. Normally spell checking is disabled for markup.raw.
    • other — other markup constructs.
  • meta — the meta scope is generally used to markup larger parts of the document. For example the entire line which declares a function would be meta.function and the subsets would be storage.type,, variable.parameter etc. and only the latter would be styled. Sometimes the meta part of the scope will be used only to limit the more general element that is styled, most of the time meta scopes are however used in scope selectors for activation of bundle items. For example in Objective-C there is a meta scope for the interface declaration of a class and the implementation, allowing the same tab-triggers to expand differently, depending on context.
  • storage — things relating to “storage”.
    • type — the type of something, class, function, int, var, etc.
    • modifier — a storage modifier like static, final, abstract, etc.
  • string — strings.
    • quoted— quoted strings.
      • single — single quoted strings: 'foo'.
      • double — double quoted strings: "foo".
      • triple — triple quoted strings: """Python""".
      • other — other types of quoting: $'shell', %s{...}.
    • unquoted — for things like here-docs and here-strings.
    • interpolated — strings which are “evaluated”: `date`, $(pwd).
    • regexp — regular expressions: /(\w+)/.
    • other — other types of strings (should rarely be used).
  • support — things provided by a framework or library should be below support.
    • function — functions provided by the framework/library. For example NSLog in Objective-C is support.function.
    • class — when the framework/library provides classes.
    • type — types provided by the framework/library, this is probably only used for languages derived from C, which has typedef (and struct). Most other languages would introduce new types as classes.
    • constant — constants (magic values) provided by the framework/library.
    • variable — variables provided by the framework/library. For example NSApp in AppKit.
    • other — the above should be exhaustive, but for everything else use support.other.
  • variable — variables. Not all languages allow easy identification (and thus markup) of these.
    • parameter — when the variable is declared as the parameter.
    • language — reserved language variables like this, super, self, etc.
    • other — other variables, like $some_variables.

13 Scope Selectors

A scope selector is a pattern much like a CSS selector which is matched against the scope of the caret (i.e. current context) and the outcome is either a match or a non-match (see also: ranking matches further down).

Scope Selector

This allows the activation method of a bundle item to be limited to contexts like “inside a comment” or “in an HTML document”. The advantage of this is that it allows a tab trigger like for to be re-used in different languages and works smoothly for mixed documents like HTML which can have embedded CSS, PHP, Ruby and JavaScript.

Scope selectors are also used with preference items and themes. In the latter case they are used to style elements of a document and in the former case to adjust various aspects of editing etc. on a granular basis.

13.1 Element Names

Generally a document consists of many different elements. A prose document may contain headings, paragraphs, bullet lists, emphasized text where source code will often contain strings, comments, keywords, storage types etc.

In TextMate the language grammars will match these elements and assign a name to each. This name should be dot separated with each additional part specializing the kind of element matched. For example a double-quoted string in C will get string.quoted.double.c assigned as its scope name (see naming conventions for more info).

A scope selector in its simplest form is an element name to match, but it only needs to specify a prefix of the actual element name. So if we specify string as our scope selector it will also match all quoted strings. Likewise if we specify string.quoted it will match single, double and triple quoted strings.

An empty scope selector will match all scopes but with the lowest possible rank (see ranking matches later).

13.2 Descendant Selectors

As with CSS, it is possible to use the context of an element in the scope selector. The picture below shows the scope for the string as a tool tip (via ⌃⇧P). The direct parent of the string is source.php.embedded.html and text.html.basic is an ancestor.

Show Scope

In the scope selector we specify element names as a space separated list to indicate that each element should be present in the scope (and in the same order). So if we want to target all strings in PHP, we can use source.php string, or we can use text.html source.php to target PHP embedded in HTML.

13.3 Excluding Elements

There are situations where we want to match a subset of a document but exclude particular subsets of this subset.

For example in Ruby it is possible to embed code in strings using #{…}, so a nice snippet would be to insert that when pressing # inside of a string. The scope selector for that would be: source.ruby string.

This unfortunately means that even inside code (embedded in strings) # will insert #{…}. To avoid this, we can subtract scope selectors to get the (asymmetric) difference using the minus operator. So a better scope selector for our snippet would be source.ruby string - string source.

Below is an illustration of what that scope selector would target.

puts "Today is #{}." ^^^^^^^^^^ ^^ 

13.4 Grouping

When we want something to match several distinct scopes, we can group scope selectors with the comma operator. For example to match both strings and comments the scope selector would be: string, comment.

13.5 Ranking Matches

If more than one scope selector matches the current scope then they are ranked according to how “good” a match they each are.

The winner is the scope selector which (in order of precedence):

  1. Match the element deepest down in the scope e.g. string wins over source.php when the scope is source.php string.quoted.
  2. Match most of the deepest element e.g. string.quoted wins over string.
  3. Rules 1 and 2 applied again to the scope selector when removing the deepest element (in the case of a tie), e.g. text source string wins over source string.

In the case of tab triggers, key equivalents and dropped files (drag commands), a menu is presented for the best matches when these are identical in rank (which would mean the scope selector in that case was identical).

For themes and preference items, the winner is undefined when multiple items use the same scope selector, though this is on a per-property basis. So for example if one theme item sets the background to blue for string.quoted and another theme item sets the foreground to white, again for string.quoted, the result would be that the foreground was taken from the latter item and background from the former.

14 Themes

TextMate uses language grammars to assign names to document elements such as strings, comments, keywords and similar. It is possible to specify particular elements using scope selectors in the same way that you can use CSS selectors to select HTML elements.

Styling a document in TextMate is similar to creating a style sheet for an HTML document. The process happens in Preferences → Fonts & Colors where one can select a theme (analogous to a style sheet), edit one of the themes or create new themes.

Fonts And Colors

Changing theme is global i.e. it is currently not possible to select a specific theme per file or file type.

A theme has six standard properties, these are the background, foreground, caret, selection, invisibles and line highlight color. In addition to that the theme consists of a list of “theme items”. Each of these items has a scope selector to select what element(s) the item should apply to and then optionally a foreground and background color and a font style (bold, italic and underline).

Remove Color

If a theme item currently has no foreground or background color, you can click the FG or BG column to add one. If instead you want to remove it, drag away the color well shown in the FG or BG column until the disappearing mouse pointer shows and then release the mouse to have the color removed.

Remember that scope selectors can be complex, so it is possible to set the background for text.html source.ruby so that Ruby blocks in HTML gets a particular color for example or use string - string source to style only the part of a string which is not embedded code.

Composite Theme Colors

14.1 Sharing

The TextMate wiki has a page for custom themes where users are encouraged to share their themes.

15 Preferences Items

For settings where differing values are useful to have based on a file type or the context of the caret position in a document, the bundle editor allows you to set and specify a scope selector which selects which scope the particular settings should apply.

Currently the preferences are specified in the old-style property list format.

Preferences Editor

15.1 Completions

  • completions — an array of additional candidates when cycling through completion candidates from the current document.
  • completionCommand — a shell command (string) which should return a list of candidates to complete the current word (obtained via the TM_CURRENT_WORD variable).
  • disableDefaultCompletion — set to 1 if you want to exclude matches from the current document when asking for completion candidates (useful when you provide your own completion command).

For more info see section on completions.

15.2 Indentation

  • decreaseIndentPattern — regular expression.
  • increaseIndentPattern — regular expression.
  • indentNextLinePattern — regular expression.
  • unIndentedLinePattern — regular expression.

For more information see indentation rules.

15.3 Symbol List

  • showInSymbolList — set to 1 to include in the symbol list.
  • symbolTransformation — a “program” consisting of one or more s/«regexp»/«format»/«options»; transformations which will be applied to the extracted “symbol”.

For more information see customizing the symbol list.

15.4 Paired Characters

  • highlightPairs — an array of arrays, each containing a pair of characters where, when the caret moves over the second, the first one will be highlighted for a short moment, if found.
  • smartTypingPairs — an array of arrays, each containing a pair of characters where when the first is typed, the second will be inserted. An example is shown below. For more information see auto-paired characters.
    smartTypingPairs = ( ( '"', '"' ), ( '(', ')' ), ( '{', '}' ), ( '[', ']' ), ( '“', '”' ), ( "'", "'" ), ( '`', '`' ), ); 

15.5 Other

  • shellVariables — an array of key/value pairs. See context dependent variables.
  • spellChecking — set to 0/1 to disable/enable spell checking.

16 Key Bindings

There are basically three types of actions in TextMate and each has its own system when it comes to key bindings (yes, this is not ideal).

16.1 Bundle Items

Bundle items are commands, snippets, macros, language grammars, templates etc. and can all be found in the bundle editor (Window → Show Bundle Editor). Each of these actions has a key equivalent and an associated scope selector which can be edited from the bundle editor.

16.2 Menu Items

Menu items can be edited via System Preferences → Keyboard & Mouse. From here it is possible to change key bindings for either all applications or particular applications based on the menu items title.

This is done by pressing the plus button on the left side below the list on the Keyboard Shortcuts page, which displays the sheet shown below.

Change Menu Key Binding

Some caveats:

  1. Only key bindings which include the command modifier (⌘) will work.
  2. Dynamic menu items i.e. those which change title depending on the programs state (like Fold Current Block / Selection) should be specified with their initial title. The initial title can be found by opening the MainMenu.nib file in Interface Builder (use Show Package Contents on TextMate and navigate to Contents → Resources → English.lproj).
  3. You need to restart an application before key binding changes take effect.

An alternative to the system preferences is Menu Master from Unsanity. This allows you to change the key binding inside the application simply by hovering your mouse on the item and pressing the new key (and does not require a restart).

16.3 Text Move / Edit Actions

The last is probably the most essential, it is the keys which “just work” in the actual text editing area.

Here TextMate uses the Cocoa key bindings system where the master set of keys are defined in /System/‍Library/‍Frameworks/‍AppKit.framework/‍Resources/‍StandardKeyBinding.dict and used by all Cocoa text fields and to some degree other controls also.

The master set of keys can be augmented by ~/Library/‍KeyBindings/‍DefaultKeyBinding.dict. The most common request with respect to key bindings is to have page up/down move the caret and have home/end go to the beginning and end of the line. This article shows how this can be done.

In addition TextMate has a /path/‍to/‍‍Contents/‍Resources/‍KeyBindings.dict file with some extra key bindings which are specific to TextMate (and thus not appropriate to put in the per user global key bindings file). You can copy this file to ~/Library/‍Application Support/‍TextMate and edit it, this will then take precedence over the bundled file.

The format is explained in the blog post linked to above.

16.3.1 List of Standard Key Bindings

For a list of which keys are available by default (in OS X) please see this list of key bindings created by Jacob Rus.

Apple also has a page about standard key bindings as part of their human Interface Guidelines. TextMate conforms to these and implement majority of the keys shown on that page.

In addition TextMate has the following key bindings, which are not visible in the menus and cannot be found in the standard key binding files:

Key Action
⌥F2 Show context menu — This is equivalent to clicking the mouse at the current caret location while holding down control (⌃). If the current word is misspelled the context menu will contain spelling suggestions.
⌃⎋ Show bundle items menu — this opens the gear menu which is located in the status bar.
⌃S Forward incremental search.
⌃⇧S Backward incremental search.
Switch to the next/previous window. This keyboard shortcut is based on the physical location of the key so on many European keymaps it is instead ⌘< and ⌘> (it is the key to the left of the Z).
Switch between main window and drawer. Like the previous key this one is also based on physical location. The function is not available on Panther.
⌃⇥ Go backwards through the chain of keyboard accessible controls. Normally this would be the same as ⇤ (⇧⇥) but that one doesn’t work when the text editing control has focus. The previous keyboard accessible control in that situation is the project outline in the drawer, so this key could be considered a “bring focus to the project drawer” key.

16.4 Conventions

Modifiers Purpose
This is for primary actions mostly defined by Apple or already a de-facto standard e.g. New, Open, Save, Print, Hide, Quit, Cut, Copy, Paste, etc.
⇧⌘ Adding the shift modifier often indicates a twist on the plain key equivalent. For example

  • ⌘W is Close Tab — ⇧⌘W is Close Project (in a project)
  • ⌘T is Go to File… — ⇧⌘T is Go to Symbol…
  • ⌘V is Paste — ⇧⌘V is Paste Previous
  • ⌘Z is Undo — ⇧⌘Z is Redo


⌥⌘ Often (but definitely not always) this modifier sequence is used to toggle an option, e.g. Soft Wrap (⌥⌘W), Show Invisibles (⌥⌘I), Bookmarks (⌥⌘B), Line Numbers (⌥⌘L), Foldings at a given level (⌥⌘0-9) etc.
⌃⌥⌘ This modifier sequence is generally used for actions which open a window. For example Show Bundle Editor (⌃⌥⌘B), Show Clipboard History (⌃⌥⌘V), Show/Hide Project Drawer (⌃⌥⌘D), Show Web Preview (⌃⌥⌘P) etc.
⌃⇧ Less important bundle actions (commands and sometimes snippets) should generally use this modifier sequence.
⌃⇧⌘ This is the secondary modifier sequence for use with less important bundle actions (i.e. when the primary one is taken).
⌃⌥⇧ This is used to switch language grammar, the key is (generally) the first letter of the language grammar name.
⌃⌘ Actions related to projects are in this space, e.g. New Project, Save Project, Reveal in Project, etc.

17 Templates

A template consists of a (shell) command which generates a new file based on the template’s contents. Below is shown how an index.html file is part of the XHTML 1.1 template.

Xhtml Templates

When executing the template shell command, the working directory is set to the directory containing the template files so that these can be referenced by name only (i.e. without path) and the shell command has access to the following three environment variables (in addition to the normal variables):

  • TM_NEW_FILE — the full path, including the name of the file to be generated (i.e. the one the user entered in the GUI).
  • TM_NEW_FILE_BASENAME — the base name of the file to be generated. If TM_NEW_FILE is /tmp/foo.txt then this variable would be foo without the folder name and the file extension.
  • TM_NEW_FILE_DIRECTORY — the folder name of the file to be generated.

A template can then be instantiated either by using the menus (File → New From Template) or for projects by using the New File button in the project drawer (⇧⌘N).

New File From Template

18 Printing

To the amusement of some and the frustration of others, TextMate currently features only limited printing capabilities.

That means you can only use the document font with no syntax highlighting and no options except the standard printing options plus header and footer fields as shown below.

Printing Options

The header and footer fields support the normal variables, interpolated code using backticks and in addition has access to these two variables:

  • TM_PAGE — the current page being printed (this is the actual page number as if all pages in the document are printed, so even if you only print page 3, this variable will be 3 and not 1).
  • TM_PAGES — total number of pages in the document.

There are plans to improve the printing capabilities, but until then, there is also a command in the Source bundle (View Source as PDF) which produces a PDF from the current source using enscript and has syntax highlighting enabled for supported languages.

19 Saving Files

TextMate has a few options in the advanced preferences which affect how to save files.

Prefs Saving

19.1 Atomic Saves

Atomic saves mean that instead of overwriting the file, TextMate saves to a new file and once this succeeds, overwrites the old file. This has the advantage that if your machine should crash while saving a file, you do not run the risk of losing the contents of both the old (last-saved) and new files.

The downside is that since a new file is actually written to disk (with a new inode), you may break an alias to the file, although this happens only if you also moved the file, or will move it, since path has precedence over inodes when resolving aliases. Also, the Finder will reposition the icon of the file each time you save it (which is only a problem if the file is in a folder you keep in sight).

19.2 Creator Code

The creator code is how Classic Macs associated a file with its application. On OS X the association is mainly through the file extension, which has the advantage that if you one day get a better program (!) to handle a given file type, you only need to update the association in one place, instead of changing the creator code of all your saved files. For this reason the recommendation is to not set this or set it to Blank.

19.3 Encoding

TextMate is heavily biased toward UTF-8. UTF-8 is an ASCII compatible encoding, so using it should give no problems with existing tools such as grep, diff, ruby (the interpreter), gcc (the compiler) etc.

Since the file system uses UTF-8 for filenames, Terminal is set to UTF-8 by default (to have the result from e.g. ls show correctly). This means that if you cat a non-ASCII file in Terminal or run a script which outputs more than ASCII (e.g. uses ellipsis or curly quotes), it will only show correctly if the output is UTF-8 (unless you change Terminal’s encoding).

In addition, UTF-8 is the only encoding that can represent all the characters you can type on your Mac. Even things like the euro symbol (€) will give a problem with the older (legacy) encodings.

And as an extra bonus, UTF-8 is the only 8 bit encoding which is recognizable with a near 100% certainty, which means that as long as you use UTF-8, you should no longer experience opening a file and the text editor making a wrong guess about the encoding used (which can mess up the file if you then save it without noticing it).

A final argument for UTF-8 is that TextMate is only providing the infrastructure for a lot of functionality. All this functionality is written as scripts and these work with the current document, files in your project, the selection etc. An action might be to transform text, show a result as HTML in a new document etc. In almost all these situations, having to deal with encoding is impractical and sometimes not even possible (like if the result can not be represented using the encoding of the source), so for all this stuff, UTF-8 is assumed.

There is a post on the TextMate blog about how to handle UTF-8 in miscellaneous situations (POST’ing data to a web-server, setting the encoding for LaTeX documents, etc.).

Having said all that, it is possible to change the default encoding and if you only need to save out a single file with another encoding you can adjust that in the Save As… dialog. The list of encodings is short and it is intentionally that way. If you need to use other encodings, the current advice is to use iconv.

You can run iconv -l for a list of the hundreds of encodings it supports.

To convert a set of files to UTF-8 in the terminal, you can run something like this:

for f in *.txt; do iconv -f mac -t utf-8 "$f" >"$f.utf8"; done 

19.4 Extended Attributes (Metadata)

Starting with Tiger, OS X supports setxattr and friends.

TextMate makes use of extended attributes to store the carets position, bookmarks, what text is folded and is likely to make further use of extended attributes in the future.

For filesystems which do not natively support extended attributes (like network mounted disks), OS X instead stores the extra information in a file named ._«filename», where «filename» is the name of the original file.

Since not all users think that this extra (hidden) file is worth having in order for TextMate to remember state, it is possible to disable the use of extended attributes by quitting TextMate and running the following from the shell:

defaults write com.macromates.textmate OakDocumentDisableFSMetaData 1 

19.5 Save Automatically when Focus Is Lost

If you are working with a project where you test your work by switching to another application (e.g. Terminal or a browser) you can set TextMate to save all modified files, when the focus is lost. That way, when you switch to the other application, TextMate will automatically save all your changes.

20 Regular Expressions

20.1 Introduction

A regular expression is a domain specific language for matching text. Naively we could write a small program to match text, but this is error-prone, tedious and not very portable or flexible.

Instead we use regular expressions which describe the match as a string which (in a simple case) consists of the character types to match and quantifiers for how many times we want to have the character type matched.

For example normal letters and digits match literally. Something like \w will match word characters, where \s will match whitespace characters (space, tab, newline, etc.). The period (.) will match any character (except newline).

The basic quantifiers are the asterisk (*) to specify that the match should happen zero or more times, plus (+) for one or more times, or a range can be given as {min,max}.

This alone gives us capabilities like finding words (\w+) or finding an image tag with an alt argument (<img.*alt=".*">).

Matching longer text sequences is one thing, but often we are interested in the subset of the match. For example, in the above example we may want to replace the alt argument text. If we enclose part of the regular expression with parentheses, we capture that part in a variable that can be used in the replacement string. The format of the replacement string is described at the end of this section, but to refer to the first capture, we use $1, $2 for the second etc.

So to change the alt argument text we could search for (<img.*alt=").*(">) and replace that with $1Text Intentionally Removed$2.

Note that in the examples above .* is used. The asterisk operator is however greedy, meaning that it will match as many characters as possible (which still allow a match to occur), so often we want to change it to non-greedy by adding ?, making it .*?.

20.1.1 External Resources

20.2 Regular Expressions in TextMate

Here is a list of places where TextMate makes use of regular expressions:

  • Filtering which files should be shown in folder references (added to projects) is done by providing regular expressions.
  • Find and Find in Project both allow regular expression replacements.
  • Folding markers are found via regular expressions.
  • Indentation calculations are based on regular expression matches.
  • Language grammars are basically a tree (with cycles) that have regular expressions in each node.
  • Snippets allow regular expression replacements to be applied to variables and (in realtime) mirrored placeholders.

So needless to say, these play a big role in TextMate. While you can live a happy life without knowing about them, it is strongly recommended that you do pick up a book, tutorial or similar to get better acquainted with these (if you are not already).

In addition to TextMate, many common shell commands support regular expressions (sed, grep, awk, find) and popular scripting languages like Perl and Ruby have regular expressions ingrained deep into the language.

20.3 Syntax (Oniguruma)

TextMate uses the Oniguruma regular expression library by K. Kosako.

The following is taken from

Oniguruma Regular Expressions Version 5.6.0 2007/04/03 syntax: ONIG_SYNTAX_RUBY (default) 1. Syntax elements \ escape (enable or disable meta character meaning) | alternation (...) group [...] character class 2. Characters \t horizontal tab (0x09) \v vertical tab (0x0B) \n newline (0x0A) \r return (0x0D) \b back space (0x08) \f form feed (0x0C) \a bell (0x07) \e escape (0x1B) \nnn octal char (encoded byte value) \xHH hexadecimal char (encoded byte value) \x{7HHHHHHH} wide hexadecimal char (character code point value) \cx control char (character code point value) \C-x control char (character code point value) \M-x meta (x|0x80) (character code point value) \M-\C-x meta control char (character code point value) (* \b is effective in character class [...] only) 3. Character types . any character (except newline) \w word character Not Unicode: alphanumeric, "_" and multibyte char. Unicode: General_Category -- (Letter|Mark|Number|Connector_Punctuation) \W non word char \s whitespace char Not Unicode: \t, \n, \v, \f, \r, \x20 Unicode: 0009, 000A, 000B, 000C, 000D, 0085(NEL), General_Category -- Line_Separator -- Paragraph_Separator -- Space_Separator \S non whitespace char \d decimal digit char Unicode: General_Category -- Decimal_Number \D non decimal digit char \h hexadecimal digit char [0-9a-fA-F] \H non hexadecimal digit char Character Property * \p{property-name} * \p{^property-name} (negative) * \P{property-name} (negative) property-name: + works on all encodings Alnum, Alpha, Blank, Cntrl, Digit, Graph, Lower, Print, Punct, Space, Upper, XDigit, Word, ASCII, + works on EUC_JP, Shift_JIS Hiragana, Katakana + works on UTF8, UTF16, UTF32 Any, Assigned, C, Cc, Cf, Cn, Co, Cs, L, Ll, Lm, Lo, Lt, Lu, M, Mc, Me, Mn, N, Nd, Nl, No, P, Pc, Pd, Pe, Pf, Pi, Po, Ps, S, Sc, Sk, Sm, So, Z, Zl, Zp, Zs, Arabic, Armenian, Bengali, Bopomofo, Braille, Buginese, Buhid, Canadian_Aboriginal, Cherokee, Common, Coptic, Cypriot, Cyrillic, Deseret, Devanagari, Ethiopic, Georgian, Glagolitic, Gothic, Greek, Gujarati, Gurmukhi, Han, Hangul, Hanunoo, Hebrew, Hiragana, Inherited, Kannada, Katakana, Kharoshthi, Khmer, Lao, Latin, Limbu, Linear_B, Malayalam, Mongolian, Myanmar, New_Tai_Lue, Ogham, Old_Italic, Old_Persian, Oriya, Osmanya, Runic, Shavian, Sinhala, Syloti_Nagri, Syriac, Tagalog, Tagbanwa, Tai_Le, Tamil, Telugu, Thaana, Thai, Tibetan, Tifinagh, Ugaritic, Yi 4. Quantifier greedy ? 1 or 0 times * 0 or more times + 1 or more times {n,m} at least n but not more than m times {n,} at least n times {,n} at least 0 but not more than n times ({0,n}) {n} n times reluctant ?? 1 or 0 times *? 0 or more times +? 1 or more times {n,m}? at least n but not more than m times {n,}? at least n times {,n}? at least 0 but not more than n times (== {0,n}?) possessive (greedy and does not backtrack after repeated) ?+ 1 or 0 times *+ 0 or more times ++ 1 or more times ({n,m}+, {n,}+, {n}+ are possessive op. in ONIG_SYNTAX_JAVA only) ex. /a*+/ === /(?>a*)/ 5. Anchors ^ beginning of the line $ end of the line \b word boundary \B not word boundary \A beginning of string \Z end of string, or before newline at the end \z end of string \G matching start position 6. Character class ^... negative class (lowest precedence operator) x-y range from x to y [...] set (character class in character class) ..&&.. intersection (low precedence at the next of ^) ex. [a-w&&[^c-g]z] ==> ([a-w] AND ([^c-g] OR z)) ==> [abh-w] * If you want to use '[', '-', ']' as a normal character in a character class, you should escape these characters by '\'. POSIX bracket ([:xxxxx:], negate [:^xxxxx:]) Not Unicode Case: alnum alphabet or digit char alpha alphabet ascii code value: [0 - 127] blank \t, \x20 cntrl digit 0-9 graph include all of multibyte encoded characters lower print include all of multibyte encoded characters punct space \t, \n, \v, \f, \r, \x20 upper xdigit 0-9, a-f, A-F word alphanumeric, "_" and multibyte characters Unicode Case: alnum Letter | Mark | Decimal_Number alpha Letter | Mark ascii 0000 - 007F blank Space_Separator | 0009 cntrl Control | Format | Unassigned | Private_Use | Surrogate digit Decimal_Number graph [[:^space:]] && ^Control && ^Unassigned && ^Surrogate lower Lowercase_Letter print [[:graph:]] | [[:space:]] punct Connector_Punctuation | Dash_Punctuation | Close_Punctuation | Final_Punctuation | Initial_Punctuation | Other_Punctuation | Open_Punctuation space Space_Separator | Line_Separator | Paragraph_Separator | 0009 | 000A | 000B | 000C | 000D | 0085 upper Uppercase_Letter xdigit 0030 - 0039 | 0041 - 0046 | 0061 - 0066 (0-9, a-f, A-F) word Letter | Mark | Decimal_Number | Connector_Punctuation 7. Extended groups (?#...) comment (?imx-imx) option on/off i: ignore case m: multi-line (dot(.) match newline) x: extended form (?imx-imx:subexp) option on/off for subexp (?:subexp) not captured group (subexp) captured group (?=subexp) look-ahead (?!subexp) negative look-ahead (?<=subexp) look-behind (?<!subexp) negative look-behind Subexp of look-behind must be fixed character length. But different character length is allowed in top level alternatives only. ex. (?<=a|bc) is OK. (?<=aaa(?:b|cd)) is not allowed. In negative-look-behind, captured group isn't allowed, but shy group(?:) is allowed. (?>subexp) atomic group don't backtrack in subexp. (?<name>subexp), (?'name'subexp) define named group (All characters of the name must be a word character.) Not only a name but a number is assigned like a captured group. Assigning the same name as two or more subexps is allowed. In this case, a subexp call can not be performed although the back reference is possible. 8. Back reference \n back reference by group number (n >= 1) \k<name> back reference by group name \k'name' back reference by group name In the back reference by the multiplex definition name, a subexp with a large number is referred to preferentially. (When not matched, a group of the small number is referred to.) * Back reference by group number is forbidden if named group is defined in the pattern and ONIG_OPTION_CAPTURE_GROUP is not setted. back reference with nest level \k<name+n> n: 0, 1, 2, ... \k<name-n> n: 0, 1, 2, ... \k'name+n' n: 0, 1, 2, ... \k'name-n' n: 0, 1, 2, ... Destinate relative nest level from back reference position. ex 1. /\A(?<a>|.|(?:(?<b>.)\g<a>\k<b+0>))\z/.match("reer") ex 2. r = Regexp.compile(<<'__REGEXP__'.strip, Regexp::EXTENDED) (?<element> \g<stag> \g<content>* \g<etag> ){0} (?<stag> < \g<name> \s* > ){0} (?<name> [a-zA-Z_:]+ ){0} (?<content> [^<&]+ (\g<element> | [^<&]+)* ){0} (?<etag> </ \k<name+1> >){0} \g<element> __REGEXP__ p r.match('<foo>f<bar>bbb</bar>f</foo>').captures 9. Subexp call ("Tanaka Akira special") \g<name> call by group name \g'name' call by group name \g<n> call by group number (n >= 1) \g'n' call by group number (n >= 1) * left-most recursive call is not allowed. ex. (?<name>a|\g<name>b) => error (?<name>a|b\g<name>c) => OK * Call by group number is forbidden if named group is defined in the pattern and ONIG_OPTION_CAPTURE_GROUP is not setted. * If the option status of called group is different from calling position then the group's option is effective. ex. (?-i:\g<name>)(?i:(?<name>a)){0} match to "A" 10. Captured group Behavior of the no-named group (...) changes with the following conditions. (But named group is not changed.) case 1. /.../ (named group is not used, no option) (...) is treated as a captured group. case 2. /.../g (named group is not used, 'g' option) (...) is treated as a no-captured group (?:...). case 3. /..(?<name>..)../ (named group is used, no option) (...) is treated as a no-captured group (?:...). numbered-backref/call is not allowed. case 4. /..(?<name>..)../G (named group is used, 'G' option) (...) is treated as a captured group. numbered-backref/call is allowed. where g: ONIG_OPTION_DONT_CAPTURE_GROUP G: ONIG_OPTION_CAPTURE_GROUP ('g' and 'G' options are argued in ruby-dev ML) ----------------------------- A-1. Syntax depend options + ONIG_SYNTAX_RUBY (?m): dot(.) match newline + ONIG_SYNTAX_PERL and ONIG_SYNTAX_JAVA (?s): dot(.) match newline (?m): ^ match after newline, $ match before newline A-2. Original extensions + hexadecimal digit char type \h, \H + named group (?<name>...), (?'name'...) + named backref \k<name> + subexp call \g<name>, \g<group-num> A-3. Lacked features compare with perl 5.8.0 + \N{name} + \l,\u,\L,\U, \X, \C + (?{code}) + (??{code}) + (?(condition)yes-pat|no-pat) * \Q...\E This is effective on ONIG_SYNTAX_PERL and ONIG_SYNTAX_JAVA. A-4. Differences with Japanized GNU regex(version 0.12) of Ruby 1.8 + add character property (\p{property}, \P{property}) + add hexadecimal digit char type (\h, \H) + add look-behind (?<=fixed-char-length-pattern), (?<!fixed-char-length-pattern) + add possessive quantifier. ?+, *+, ++ + add operations in character class. [], && ('[' must be escaped as an usual char in character class.) + add named group and subexp call. + octal or hexadecimal number sequence can be treated as a multibyte code char in character class if multibyte encoding is specified. (ex. [\xa1\xa2], [\xa1\xa7-\xa4\xa1]) + allow the range of single byte char and multibyte char in character class. ex. /[a-<<any EUC-JP character>>]/ in EUC-JP encoding. + effect range of isolated option is to next ')'. ex. (?:(?i)a|b) is interpreted as (?:(?i:a|b)), not (?:(?i:a)|b). + isolated option is not transparent to previous pattern. ex. a(?i)* is a syntax error pattern. + allowed incompleted left brace as an usual string. ex. /{/, /({)/, /a{2,3/ etc... + negative POSIX bracket [:^xxxx:] is supported. + POSIX bracket [:ascii:] is added. + repeat of look-ahead is not allowed. ex. /(?=a)*/, /(?!b){5}/ + Ignore case option is effective to numbered character. ex. /\x61/i =~ "A" + In the range quantifier, the number of the minimum is omissible. /a{,n}/ == /a{0,n}/ The simultanious abbreviation of the number of times of the minimum and the maximum is not allowed. (/a{,}/) + /a{n}?/ is not a non-greedy operator. /a{n}?/ == /(?:a{n})?/ + invalid back reference is checked and cause error. /\1/, /(a)\2/ + Zero-length match in infinite repeat stops the repeat, then changes of the capture group status are checked as stop condition. /(?:()|())*\1\2/ =~ "" /(?:\1a|())*/ =~ "a" A-5. Disabled functions by default syntax + capture history (?@...) and (?@<name>...) ex. /(?@a)*/.match("aaa") ==> [<0-1>, <1-2>, <2-3>] see sample/listcap.c file. A-6. Problems + Invalid encoding byte sequence is not checked in UTF-8. * Invalid first byte is treated as a character. /./u =~ "\xa3" * Incomplete byte sequence is not checked. /\w+/ =~ "a\xf3\x8ec" // END 

20.4 Replacement String Syntax (Format Strings)

When you perform a regular expression replace, the replace string is interpreted as a format string which can reference captures, perform case foldings, do conditional insertions (based on capture registers) and support a minimal amount of escape sequences.

20.4.1 Captures

To reference a capture, use $n where n is the capture register number. Using $0 means the entire match.


 Find: <img src="(.*?)"> Replace: <img src="$1" alt="$1"> 

20.4.2 Case Foldings

It is possible to convert the next character to upper or lowercase by prepending it with \u or \l. This is mainly useful when the next character stems from a capture register. Example:

 Find: (<a.*?>)(.*?)(</a>) Replace: $1\u$2$3 

You can also convert a longer sequence to upper or lowercase by using \U or \L and then \E to disable the case folding again. Example:

 Find: (<a.*?>)(.*?)(</a>) Replace: $1\U$2\E$3 

20.4.3 Conditional Insertions

There are times where the replacements depends on whether or not something was matched. This can be done using (?«n»:«insertion») to insert «insertion» if capture «n» was matched. You can also use (?«n»:«insertion»:«otherwise») to have «otherwise» inserted when capture «n» was not matched.

To make a capture conditional either place it in an alternation, e.g. foo|(bar)|fud or append a question mark to it: (bar)?. Note that (.*) will result in a match, even when zero characters are matched, so use (.+)? instead.

So for example if we wish to truncate text to eight words and insert ellipsis only if there were more than eight words, we can use:

 Find: (\w+(?:\W+\w+){,7})\W*(.+)? Replace: $1(?2:…) 

Here we first match a word (\w+) followed by up to seven words ((?:\W+\w+){,7}) each preceded by non-word characters (spacing). Then optionally put anything following that (separated by non-word characters) into capture register 2 ((.+)?).

The replacement first inserts the (up to) eight words matched ($1) and then only if capture 2 matched something, ellipsis ((?2:…)).

20.4.4 Escape Codes

In addition to the case folding escape codes, you can insert a newline character with \n, a tab character with \t and a dollar sign with \$.

21 Calling TextMate from Other Applications

21.1 Shell / Terminal

Mac OS X comes with an open shell command which can be used to simulate a double click from within Terminal. It can also perform an Open With… operation by use of the -a argument, e.g.: open -a TextMate . will open the current folder in TextMate (as a scratch project).

This standard command has a few shortcomings: it can only open one file at a time, it cannot open a document at a specific line and it cannot “stall” the shell until the file has been closed, which is useful e.g. when using an editor to write something like a subversion commit message.

For this reason TextMate comes with its own mate shell command, which supersedes the open command. For usage instructions you can run mate -h (from Terminal).

The mate command is located inside the TextMate application bundle and it is recommended that you create a symbolic link which points to the command (rather than “install” it), so that if the command is updated in the future, you will not need to reinstall the updated command.

Creating a symbolic link can either be done by selecting Help → Terminal Usage… from the menu, or from the shell by running something like the following:

ln -s /Applications/ ~/bin/mate 

This assumes that you have ~/bin created and in your path and that TextMate is installed in /Applications.

After having created this link, you may want to setup a few shell variables to make other applications use TextMate as an external editor.

21.1.1 The General EDITOR Variable

The EDITOR variable is used by many shell commands, like svn (subversion) and CVS. To use TextMate as the editor for the EDITOR variable, set it like this (for bash and zsh users e.g. in ~/.bash_profile or ~/.zshrc):

export EDITOR='mate -w' 

We add the -w argument to make the command wait for TextMate to close the file, before continuing.

There is one command which does not support giving arguments in the EDITOR variable, it is crontab (which is sort of obsoleted by launchd). If you need to use it, you can create a symbolic link to mate with a _wait suffix which implies -w. For example:

ln -s mate ~/bin/mate_wait # run this once to create the link export EDITOR='mate_wait' # use in your ~/.bash_profile 

21.1.2 Git Editor

When you commit to a Git repository you may find that your caret is not at the first line.

This is because Git reuses the temporary file used for the commit message and TextMate stores per-file caret position (via extended attributes).

To avoid this problem you can set the Git editor to mate -wl1. This instructs TextMate to open with the caret at line 1 rather than where it last was.

To set it like this for Git, you can set the GIT_EDITOR variable or Git’s core.editor configuration variable.

21.1.3 TeX Editor

When TeX gives an error message relating to a file, you can enter e to edit the file (and correct the error).

To setup TextMate to be used in this case, setup the TEXEDIT variable like this:

export TEXEDIT='mate -w -l %d "%s"' 

21.1.4 Edit from less

The less pager supports editing the file being viewed by pressing v. To setup TextMate to be used with less, you need to setup the LESSEDIT variable:

export LESSEDIT='mate -l %lm %f' 

21.2 URL Scheme (HTML)

The txmt URL scheme allows you to open files in TextMate via hyperlinks found for example in HTML documents (anchors). These can refer to local files which can be useful when:

  1. Using commands with HTML output that indicate errors/warnings with the current document, or refer to other documents in your project.
  2. If you are generating a set of web-pages from simpler (text) files you can have these link to the original text files, so that when you are inspecting the generated result (in a browser) you can quickly edit the source of each page by following the txmt:-link.

The URL scheme is txmt: and currently has one command named open. This command takes up to three arguments:

  • url — the (file) URL to open (e.g. url=file://~/.bash_profile), if this is left out, the current document is targeted.
  • line — the line on which the caret should be placed after opening the file (e.g. line=11).
  • column — the column on which the caret should be placed after opening the file (e.g. column=3).

So a full example of a txmt: URL could be (click here to test):


21.3 ODB Editor Suite

TextMate implements the server side of the ODB Editor Suite. This allows it to be used as external editor for programs which implement the client side of the protocol.

Many programs do however use a hardcoded list of which text editors implement the protocol, so if you cannot find TextMate in the list of external editors for an application which does support the ODB Editor Suite, you may need to write to the author of that application and request that TextMate gets added to its list of supported editors.

There is a wiki page which tracks the status of applications that can be configured to use an external text editor.

21.4 Cocoa Text Fields

Included with TextMate is an “Edit in TextMate” input manager which you can install to get the ability to call upon TextMate from the standard Cocoa text editor control (including the one used in Mail). This is useful for programs which do not implement the ODB Editor Suite (e.g. Safari’s form elements).

For more info select the Install “Edit in TextMate”… action located in the TextMate bundle (using the gear menu in the status bar). This provides you with full documentation about the input manager before actually installing it.

22 Expert Preferences

TextMate has a few settings which are not exposed in the GUI.

You can change these with the defaults shell command but you need to do this while TextMate is not running.

You set a key to a given value with the following syntax:

defaults write com.macromates.textmate «key» «value» 

You can always reset a key to its default value using:

defaults delete com.macromates.textmate «key» 

Or you can read the value of a key using:

defaults read com.macromates.textmate «key» 

22.1 NSDragAndDropTextDelay

When you press mouse down on the selection and move the mouse, TextMate will start a new selection, unless you wait 150 milliseconds, then it will instead drag the selection. This delay can be changed by adjusting this preferences value.

Setting it to a value less than zero (e.g. -1) will disable the ability to drag a selection, meaning clicking the mouse inside a selection immediately deselects it and starts a new selection from that point (if the mouse is moved while the button is down).

Setting it to zero will immediately start a drag.


defaults write com.macromates.textmate NSDragAndDropTextDelay 0 

22.2 NSRecentDocumentsLimit

This sets the number of documents kept in the “Open Recent” menu. The default value is 25.


defaults write com.macromates.textmate NSRecentDocumentsLimit 50 

22.3 OakBundleItemsPopUpMenuKeyEquivalent

The key equivalent which should open the gear menu in the status bar. This is a key equivalent description as used in the system key bindings file. The default value is “^\033” (control escape).

For more information about key codes see this letter.

22.4 OakBundleManagerDisambiguateMenuFontSize

If you find the font used in the menu to disambiguate tab triggers, key equivalents and similar, too small, then you can run:

defaults write com.macromates.textmate OakBundleManagerDisambiguateMenuFontSize 14 

22.5 OakDefaultBundleForNewBundleItems

When you create a new item in the bundle editor without having selected a bundle first, then the bundle with the UUID held by this defaults key is used as the target.

This automatically gets set to the first bundle you create. For an example of how to change it see this letter.

22.6 OakDefaultLanguage

Sets the default language used for new (untitled) documents. The value should be the UUID of the language to be used.

For more information see this message from the mailing list.

22.7 OakDisableSessionRestore

When you launch TextMate it will open the project / document which was open when you last exited. You can however disable this feature by running:

defaults write com.macromates.textmate OakDisableSessionRestore 1 

22.8 OakDocumentCustomFSMetaData

An array of file systems for which TextMate should use its own functions for storing meta data (setxattr replacement). The meta data is stored in AppleDouble format. The default value is ( afpfs, nfs, msdos ) since setxattr can cause a kernel panic for these file systems (rdar://4162474).


defaults write com.macromates.textmate \ OakDocumentCustomFSMetaData '( afpfs, nfs, msdos, hfs )' 

22.9 OakDocumentDisableFSMetaData

See extended attributes for more info.

22.10 OakFindPanelDisableHistory

This disables the history controls in the find panel. The reason for this setting is only because some users have experienced crashes when using the tab key in the find dialog and this is caused by the history controls used. Currently the only workaround is to disable the use of these controls:

defaults write com.macromates.textmate OakFindPanelDisableHistory 1 

22.11 OakToolTipMouseMoveIgnorePeriod and OakToolTipMouseDistanceThreshold

When a command brings up a tool tip, mouse movements performed within the first second do not close the tool tip and after that second has elapsed, the mouse needs to be moved at least 5 pixels for the tool tip to close. These values can be adjusted using the OakToolTipMouseMoveIgnorePeriod and OakToolTipMouseDistanceThreshold defaults keys.

22.12 OakWrapColumns

This is an array of the values which appear in the View → Wrap Column submenu. Defaults to showing 40 and 78 as possible wrap columns.


defaults write com.macromates.textmate OakWrapColumns '( 60, 70, 80, 120 )' 

22.13 OakWordsExcludedFromCapitalization

The Text → Convert → to Titlecase action (⌃⌥U) excludes words found in this array.

The default value is ( a, an, and, at, but, by, else, for, from, if, in, nor, of, off, on, or, out, over, the, then, to, up, when ).

23 Getting Help

23.1 Mailing List

There is a mailing list for TextMate. The archive is public and you can search it with this form:

23.2 IRC Channel

There is a ##textmate IRC channel on

23.3 Other Resources

23.3.1 TextMate Cheat Sheet

David Powers has created a succinct cheat sheet (direct link to PDF) which you can print and have next to your computer. It lists key equivalents for many useful general actions.

23.3.2 TextMate Tutorials

Soryu has written two TextMate tutorials dealing with setup and basic usage.

23.3.3 Screencasts

You can subscribe to the screencast RSS feed via iTunes.

Here is a list with direct links to a few of the screencasts in recommended viewing order:

For the full list with a brief summary see the online screencast page.

24 Appendix

24.1 Property List Format

Normally TextMate presents settings and such using a GUI, but for the language grammars and preferences items it exposes you to the old-style property list format.

For the purposes of TextMate this format has 3 data types which are described below. Notice that the escape rules for strings have been changed slightly compared to Apple’s official format. This was done to make the language grammars more readable, since these need a lot of literal escape characters.

24.1.1 Strings

The basic type is a string which can be either single or double quoted.

When the string is single quoted, all characters are verbatim. If you need to put a ' inside a single quoted string, you need to use two, for example:

'Normal string' => Normal string 'That''s an apostrophe' => That's an apostrophe 'String with \backslash' => String with \backslash 

As you can see, the only interpretation which happens is to convert any occurrence of '' to a single '.

Double quoted strings do support escape sequences, apart from \" and \\. For example:

"Normal string" => Normal string "Some \"quoted\" text" => Some "quoted" text "Literal \escape" => Literal \escape "Escaped \\escape" => Escaped \escape "Two \\\escapes" => Two \\escapes 

When a string consists entirely of letters, underscores and dashes, it is possible to omit the quotes. For example the following are all legal strings:

foreground-color this_is_a_string justLettersInThisOne 

24.1.2 Arrays

Arrays are collections of elements, each element can be another array, a string or a dictionary. Elements are comma separated and the entire list is enclosed in parentheses. Some examples:

( "foo", "bar", "fud" ) ( "nested", ( "array", "in" ), "array" ) 

It is allowable to put a comma after the last element, like this:

( "foo", "bar", "fud", ) 

24.1.3 Dictionaries

Dictionaries associate a value with a name (key). They are also known as maps, hashes, associative arrays and probably go under a few other terms as well.

The structure is: { «key» = «value»; } here «key» is a string and «value» can be either an array, string or another dictionary. Some examples:

{ color = "black"; } { colors = ( "red", "green", "blue" ); } 

24.2 Indentation Rules

24.2.1 Introduction

Source code and structured text generally have indentation conventions. TextMate can help you with these if you tell it when to increase and decrease the indent.

Having TextMate figure out the proper indentation is useful when you paste text in another part of the source (where the indentation is different), when you press return on a line that affects the indentation (for next line), or when you press tab at the beginning of the line (and want as much indentation as appropriate for that line).

24.2.2 The System

Some languages go a little beyond a single character/keyword to increase and another to decrease, so TextMate has four (regexp) patterns you can set to tell it about your indentation conventions.

The patterns should be set in the Bundle Editor and are set as preference items with the scope set to the scope for which you want the rules to apply (e.g. source.c++).

Indentation Rules

We will use the following code example to explain the four patterns:

 1 int main (int argc, char const* argv[]) 2 { 3 while(true) 4 { 5 if(something()) 6 break; 7 #if 0 8 play_awful_music(); 9 #else 10 play_nice_music(); 11 #endif 12 } 13 return 0; 14 } 

24.2.3 Increase Pattern

The increaseIndentPattern should match the lines which increase the indent. In our example above, this is the { characters at lines 2 and 4 (the if on line 5 will be discussed later).

The simple preference for this pattern would be:

increaseIndentPattern = '\{'; 

However, since we could have code like this:

int arr[] = { 1, 2, 3 }; 


str = "foo {"; 

we need to make it a little more complicated, by ensuring that no }, " or ' will follow the { on the same line. A good choice for languages which use the bracket to start a block would be:

increaseIndentPattern = "^.*\{[^}\"']*$"; 

24.2.4 Decrease Pattern

The decreaseIndentPattern should match the counterpart of our increase indent pattern. In our example the indent is increased by lines 12 and 14. The character here is } and so the simple decrease indent pattern would be setup as:

decreaseIndentPattern = '\}'; 

the more complex version may allow only comment end markers in front of the } and whitespace or ; after the }, so with that in mind, we extend the pattern to:

decreaseIndentPattern = '^(.*\*/)?\s*\}[;\s]*$'; 

24.2.5 Increase Only Next Line

We ignored line 5 in the increase indent pattern, that is because it does not really increase the indent, it only causes the next line to be indented if a block is not started.

For this situation there is the indentNextLinePattern, which should match these lines. We could make it something like:

indentNextLinePattern = 'if|while|for|switch|…'; 

But generally in C-like languages, all lines not terminated with a semi-colon (or ending with starting a block), cause the next line to be indented. This is (with most conventions) also the case when manually breaking one expression into several lines, e.g.:

some_function(argument1, argument2, argument3); more_code; 

So instead of explicitly matching known language constructs which have the next line indented, we simply match all lines which are not terminated with a semi-colon or brackets. One thing to remember is single-line comments like this:

some_function(arg); // this is terminated 

To solve that, we start with a negative look-ahead assertion in this case and then go on to match lines not terminated by any of the characters mentioned above. The pattern ends up as:

indentNextLinePattern = '^(?!.*;\s*//).*[^\s;{}]\s*$'; 

24.2.6 Ignoring Lines

Sometimes we have lines which are outside the normal indent, or does not affect the indent despite matching our rather general indentNextLinePattern. In our example these are the preprocessor lines (line 7, 9 and, 11).

To tell TextMate about these lines, there is an unIndentedLinePattern rule. Another case to avoid might be something like this:

 1 some_function(); 2 3 /* ignore_first(); 4 ignore_second(); 5 */ 6 more_functions(); 

Here line 3 and 5 would count as having zero indent, so we want to ignore these.

To instruct it to ignore preprocessor lines, lines with leading comments or a few Objective-C directives (which are not terminated by a semi-colon), we can use this pattern:

unIndentedLinePattern = '^\s*((/\*|\*/\s*$|//|#|@interface|@implementation|@end).*)?$'; 

24.3 Plug-in API

When launched, TextMate loads plug-ins located in ~/‍Library/‍Application Support/‍TextMate/‍PlugIns. The plug-in should be a normal Objective-C bundle with a principal class which will receive an initWithPlugInController: when instantiated.

There is a sample plug-in here. Though other than the startup message, TextMate does not offer any API for the plug-in to use (but will likely do so in the future).

If you are interested in developing plug-ins for TextMate, you can subscribe to the plug-ins mailing list.

VPN entre servidores CentOS 6 e Windows 7

 Leitura Recomendada, Linux, Redes  Comentários desativados em VPN entre servidores CentOS 6 e Windows 7
ago 092012

Configuração dos servidores e do OpenVPN

Neste artigo, estou explicando o passo a passo sobre como implantar uma VPN utilizando OpenVPN com servidores CentOS 6, ou Red Hat, e Clientes Windows 7.

Este cenário é muito usado em empresas que possuem uma matriz e tem consultores externos que precisam ter acesso aos servidores de dados da matriz.

Primeiro passo, vamos configurar o servidor OpenVPN que fará a autenticação dos usuários:

1. Instale os pacotes:

# yum install gcc rpm-build autoconf.noarch zlib-devel pam-devel lzo lzo-devel openssl-devel automake imake pkgconfig gcc-c++

2. Faça Download dos pacotes:

$ wget
$ wget
$ wget
$ wget

3. Instale os pacotes baixados:

# rpmbuild –rebuild lzo-1.08-4.rf.src.rpm
# rpm -Uvh /root/rpmbuild/RPMS/i386/lzo-*.rpm
# rpm -ivh pkcs11-helper-*.rpm
# rpmbuild -tb openvpn-2.1.3.tar.gz
# rpm -Uvh /root/rpmbuild/RPMS/i386/openvpn-2.1.3-1.i386.rpm

4. Na sequência, crie um diretório chamado “openvpn” dentro do /etc:

# mkdir /etc/openvpn

5. Entre dentro do diretório /etc/openvpn:

# cd /etc/openvpn

6. Copie o diretório /usr/share/doc/openvpn-2.1.3/easy-rsa/2.0/ para dentro do /etc/openvpn:

# cp -r /usr/share/doc/openvpn-2.1.3/easy-rsa/2.0/

7. Dentro do diretório etc/openvpn/2.0, contém os scripts necessários para configuração da VPN:

8. Entre no diretório que acabou de copiar (/etc/openvpn/2.0) e vamos editar o arquivo vars (use o editor de texto de sua preferência, eu vou usar Vim):

# cd /etc/openvpn/2.0
# vim vars

9. Troque os parâmetros abaixo, pelos de sua empresa e salve o arquivo:

10. Agora, vamos carregar estes arquivos na memória, para que os mesmos sejam colocados com variáveis de ambiente:

# source ./vars

11. Vamos executar o script clean-all, para que seja limpo todas as chaves e não haja conflito de variáveis:

# ./clean-all

12. Agora vamos começar a criar as autoridades certificadoras e os certificados:


O mesmo irá trazer os valores padrões, até mesmo porque editamos o arquivo vars, apenas confime pressionando ENTER, para concluir a criação da autoridade certificadora.

13. A partir de agora, foi criado um diretório chamado “Keys” onde contém os certificados da (CA).

Obs.: É importante que este certificado exista tanto no servidor como no cliente.

14. Vamos gerar os certificados do servidor:

#./build-key-server Matriz

Obs.: Matriz é o nome do meu server.

Eu não coloco atributos extras de segurança.

Confirme os dados.

15. Após a criação do certificado, verifique no diretório Keys, que agora existe o certificado Matriz, a chave de acesso e a requisição do certificado:

  • matriz.key
  • matriz.csr
  • matriz.crt

16. Agora, vamos gerar as chaves dos meus clientes, ou consultores externos, vou chamar de “consultor1”:

#./build-key consultor1

Confirme os dados (não utilizo senha, assim, num primeiro momento poderá validar se suas chaves estão funcionando):

  • consultor1.key
  • consultor1.csr
  • consultor1.crt

17. E por fim, vamos criar o certificado Diffie hellman. Este certificado é muito importante, pois o mesmo garante que toda troca de chaves será feito com toda segurança:

# ./build–dh

18. Verifique no diretórios “Keys”, que as chaves foram criadas as chaves do CA, MATRIZ, CONSULTOR1 e DH1024.

Caso não aconteceu, verifique se não pulou nenhum passo.

19. Vamos criar um link simbólico que vai apontar para o diretório Keys:

# ln -s /2.0/keys keys

Isto vai facilitar o acesso ao diretório.

20. O próximo passo será configurar a matriz para fazer a autenticação dos usuários. Vamos criar um arquivo chamado “matriz.conf” dentro do diretório /etc/openvpn/:

# touch matriz.conf

21. Agora, só falta reiniciar o serviço VPN:

# /etc/init.d/openvpn restart

Caso exista algum problema, por favor, verifique em log.

22. Vamos configurar os cliente que será o nosso consultor1

23. Neste artigo estou utilizando o OpenVPNPortable, este aplicativo permite que o mesmo seja utilizado em um pendrive e seja executado em qualquer computador que possua Windows 7.

O Pacote contém algumas pastas:

24. No arquivo “OpenVPNPortable.ini”, temos as seguintes configurações:

* Observação: Neste arquivo, precisa ser trocado o parâmetro AutoConnect para o nome da chave criada, no caso do exemplo, estou utilizando: Consultor1

25. Dentro do diretório data, existe um diretório configque contém as chaves e o arquivo com a extensão “.ovpn”, os mesmos devem ficar da seguinte forma:

26. Acima, contém as chaves criadas no servidor que foram copiadas para dentro do diretório config, e junto com as chaves, é contido o arquivo “consultor1.ovpn”.

Neste arquivo exitem os parâmetros de configuração do cliente para conexão com o servidor. Os parâmetros devem ficar da seguinte forma:

27. Após o término das configurações do cliente, execute o arquivo OpenVPNPortable.exe:

28. O mesmo fará a conexão automática com o Servidor VPN.

29. Como dica, existem algumas observações:

  • No Windows 7, desabilite a UAC (User Account Control), caso contrário, o Windows bloqueará a criação do adaptador de rede virtual.
  • Verifique as rotas dos firewall, para liberar as portas que irão utilizar para conexão com a VPN.

Comandos Linux

 Clusterweb, Leitura Recomendada, Linux  Comentários desativados em Comandos Linux
ago 092012

Bem vindo(a) aos Comandos Linux!

Comandos Linux é um pequeno website com um conjunto de comandos Linux para uso no dia a dia, sempre que nos esquecemos de algum em particular. Sempre que se quiserem lembrar de um comando, visitem-nos e coloquem-nos nos favoritos (Pressionando as teclas Ctrl + D ao mesmo tempo).

Comandos de Controlo e Acesso
exit Terminar a sessão, ou seja, a shell (mais ajuda digitando man sh ou man csh)
logout Deslogar, ou seja, terminar a sessão actual, mas apenas na C shell e na bash shell
passwd Mudar a password do nosso utilizador
rlogin Logar de forma segura noutro sistema Unix/Linux
ssh Sessão segura, vem de secure shell, e permite-nos logar num servidor através do protocolo ssh
slogin Versão segura do rlogin
yppasswd Mudar a password do nosso utilizador nas páginas amarelas (yellow pages)


Comandos de Comunicações
mail Enviar e receber emails
mesg Permitir ou negar mensagens de terminal e pedidos de conversação (talk requests)
pine Outra forma de enviar e receber emails, uma ferramenta rápida e prática
talk Falar com outros utilizadores que estejam logados no momento
write Escrever para outros utilizadores que estejam logados no momento


Comandos de Ajuda e Documentação
apropos Localiza comandos por pesquisa de palavra-chave
find Localizar ficheiros, como por exemplo: find . -name *.txt -print, para pesquisa de ficheiros de texto por entre os ficheiros da directoria actual
info Lança o explorador de informações
man Manual muito completo, pesquisa informação acerca de todos os comandos que necessitemos de saber, como por exemplo man find
whatis Descreve o que um determinado comando é
whereis Localizar a página de ajuda (man page), código fonte, ou ficheiros binários, de um determinado programa


Comandos de Edição de Texto
emacs Editor de texto screen-oriented
pico Editor de texto screen-oriented, também chamado de nano
sed Editor de texto stream-oriented
vi Editor de texto full-screen
vim Editor de texto full-screen melhorado (vi improved)


Comandos de Gestão de Ficheiros e Directorias
cd Mudar de directoria actual, como por exemplo cd directoria, cd .., cd /
chmod Mudar a protecção de um ficheiro ou directoria, como por exemplo chmod 777, parecido com o attrib do MS-DOS
chown Mudar o dono ou grupo de um ficheiro ou directoria, vem de change owner
chgrp Mudar o grupo de um ficheiro ou directoria
cmp Compara dois ficheiros
comm Selecciona ou rejeita linhas comuns a dois ficheiros seleccionados
cp Copia ficheiros, como o copy do MS-DOS
crypt Encripta ou Desencripta ficheiros (apenas CCWF)
diff Compara o conteúdo de dois ficheiros ASCII
file Determina o tipo de ficheiro
grep Procura um ficheiro por um padrão, sendo um filtro muito útil e usado, por exemplo um cat a.txt | grep ola irá mostrar-nos apenas as linhas do ficheiro a.txt que contenham a palavra “ola”
gzip Comprime ou expande ficheiros
ln Cria um link a um ficheiro
ls Lista o conteúdo de uma directoria, semelhante ao comando dir no MS-DOS
lsof Lista os ficheiros abertos, vem de list open files
mkdir Cria uma directoria, vem de make directory”
mv Move ou renomeia ficheiros ou directorias
pwd Mostra-nos o caminho por inteiro da directoria em que nos encontramos em dado momento, ou seja a pathname
quota Mostra-nos o uso do disco e os limites
rm Apaga ficheiros, vem de remove, e é semelhante ao comando del no MS-DOS, é preciso ter cuidado com o comando rm * pois apaga tudo sem confirmação por defeito
rmdir Apaga directorias, vem de remove directory
stat Mostra o estado de um ficheiro, útil para saber por exemplo a hora e data do último acesso ao mesmo
sync Faz um flush aos buffers do sistema de ficheiros, sincroniza os dados no disco com a memória, ou seja escreve todos os dados presentes nos buffers da memória para o disco
sort Ordena, une ou compara texto, podendo ser usado para extrair informações dos ficheiros de texto ou mesmo para ordenar dados de outros comandos como por exemplo listar ficheiros ordenados pelo nome
tar Cria ou extrai arquivos, muito usado como programa de backup ou compressão de ficheiros
tee Copia o input para um standard output e outros ficheiros
tr Traduz caracteres
umask Muda as protecções de ficheiros por defeito
uncompress Restaura um ficheiro comprimido
uniq Reporta ou apaga linhas repetidas num ficheiro
wc Conta linhas, palavras e mesmo caracteres num ficheiro


Exibição ou Impressão de Ficheiros
cat Mostra o conteúdo de um ficheiro, como o comando type do MD-DOS, e é muito usado também para concatenar ficheiros, como por exemplo fazendo cat a.txt b.txt > c.txt” para juntar o ficheiro a.txt e b.txt num único de nome c.txt
fold Encurta, ou seja, faz um fold das linhas longas para caberem no dispositivo de output
head Mostra as primeiras linhas de um ficheiro, como por exemplo com head -10 a.txt, ou usado como filtro para mostrar apenas os primeiros x resultados de outro comando
lpq Examina a spooling queue da impressora
lpr Imprime um ficheiro
lprm Remove jobs da spooling queue da impressora
more Mostra o conteúdo de um ficheiro, mas apenas um ecrã de cada vez, ou mesmo output de outros comandos, como por exemplo ls | more
less Funciona como o more, mas com menos features, menos características e potenciais usos
page Funciona de forma parecida com o comando more, mas exibe os ecrãs de forma invertida ao comando more
pr Pagina um ficheiro para posterior impressão
tail Funciona de forma inversa ao comando head, mostra-nos as últimas linhas de um ficheiro ou mesmo do output de outro comando, quando usado como filtro
zcat Mostra-nos um ficheiro comprimido
xv Serve para exibir, imprimir ou mesmo manipular imagens
gv Exibe ficheiros ps e pdf
xpdf Exibe ficheiros pdf, usa o gv


Comandos de Transferência de Ficheiros
ftp Vem de file transfer protocol, e permite-nos, usando o protocolo de transferência de ficheiros ftp, transferir ficheiros entre vários hosts de uma rede, como aceder a um servidor de ftp para enviar ou puxar ficheiros
rsync Sincroniza de forma rápida e flexível dados entre dois computadores
scp Versão segura do rcp


Comandos de Notícias ou Rede
netstat Mostra o estado da rede
rsh Corre umam shell em outros sistemas UNIX
ssh Versão segura do rsh
nmap Poderoso port-scan, para visualizarmos portas abertas num dado host
ifconfig Visualizar os ips da nossa máquina, entre outras funções relacionadas com ips
ping Pingar um determinado host, ou seja, enviar pacotes icmp para um determinado host e medir tempos de resposta, entre outras coisas


Comandos de Controlo de Processos
kill Mata um processo, como por exemplo kill -kill 100 ou kill -9 100 ou kill -9 %1
bg Coloca um processo suspenso em background
fg Ao contrário do comando bg, o fg traz de volta um processo ao foreground
jobs Permite-nos visualizar jobs em execução, quando corremos uma aplicação em background, poderemos ver esse job com este comando, e termina-lo com um comando kill -9 %1, se for o job número 1, por exemplo
top Lista os processos que mais cpu usam, útil para verificar que processos estão a provocar um uso excessivo de memória, e quanta percentagem de cpu cada um usa em dado momento
^y Suspende o processo no próximo pedido de input
^z Suspende o processo actual


Comandos de Informação de Estado
clock Define a hora do processador
date Exibe a data e hora
df Exibe um resumo do espaço livre em disco
du Exibe um resumo do uso do espaço em disco
env Exibe as variáveis de ambiente
finger Pesquisa informações de utilizadores
history Lista os últimos comandos usados, muito útil para lembrar também de que comandos foram usados para fazer determinada acção no passado ou o que foi feito em dada altura
last Indica o último login de utilizadores
lpq Examina a spool queue
manpath Mostra a path de procura para as páginas do comando man
printenv Imprime as variáveis de ambiente
ps Lista a lista de processos em execução, útil para saber o pid de um processo para o mandar abaixo com o comando kill, entre outras coisas
pwd Mostra-nos o caminho por inteiro da directoria em que nos encontramos em dado momento, ou seja a pathname
set Define variáveis da sessão, ou seja, da shell, na C shell, na bash ou na ksh
spend Lista os custos ACITS UNIX até à data
time Mede o tempo de execução de programas
uptime Diz-nos há quanto tempo o sistema está funcional, quando foi ligado e o seu uptime
w Mostra-nos quem está no sistema ou que comando cada job está a executar
who Mostra-nos quem está logado no sistema
whois Serviço de directório de domínios da Internet, permite-nos saber informações sobre determinados domínios na Internet, quando um domínio foi registado, quando expira, etc
whoami Diz-nos quem é o dono da shell


Comandos de Processamento de Texto
abiword Processador de Texto Open Source
addbib Cria ou modifica bases de dados bibliográficas
col Reverte o filtro a line feeds
diction Identifica sentenças com palavras
diffmk Marca diferenças entre ficheiros
dvips Converte ficheiros TeX DVI em ficheiros PostScript
explain Explica frases encontradas pelo programa diction
grap Preprocessador pic para desenhar gráficos, usado em tarefas elementares de análises de dados
hyphen Encontra palavras com hífenes
ispell Verifica a ortografia de forma interactiva
latex Formata texto em LaTeX, que é baseado no TeX
pdfelatex Para documentos LaTeX em formato pdf
latex2html Converter LaTeX para html
lookbib Encontra referências bibliográficas
macref Cria uma referência cruzada listando ficheiros de macros nroff/troff
ndx Cria uma página de indexação para um documento
neqn Formata matemáticas com nroff
nroff Formata texto para exibição simples
pic Produz simples imagens para troff input
psdit Filtra um output troff para a Apple LaserWriter
ptx Cria uma indexação permutada mas não em CCWF
refer Insere referências de bases de dados bibliográficas
roffbib Faz o run off de uma base de dados bibliográfica
sortbib Ordena uma base de dados bibliográfica
spell Encontra erros de ortografia
style Analisa as características superficiais de um documento
tbl Formata tabelas para nroff/troff
tex Formata texto
tpic Converte ficheiros pic source em comandos TeX
wget Permite-nos fazer o download completo de páginas web, com todos os ficheiros, de forma fácil e não interactiva, sem exigir por isso presença do utilizador, respeitando também o ficheiro robots.txt


html2ps Conversor de html para ps
latex2html Conversor de LaTeX para html
lynx Navegador web baseado em modo de texto, ou seja, é um web browser que nos permite abrir todo o tipo de páginas visualizando apenas os textos e links, não vendo assim as imagens, e sendo por isso bastante rápido, mas requere prática para ser manuseado
netscape Navegador web da Netscape
sitecopy Aplicação que nos permite manter facil e remotamente web sites
weblint Verificador de sintaxes e de estilos html

Consultas SQL pelo Terminal no Postgres, Mysql, SQL Server

 Clusterweb, Linux, Redes  Comentários desativados em Consultas SQL pelo Terminal no Postgres, Mysql, SQL Server
ago 092012


No meu dia a dia, e de muitos que possam está lendo este artigo, tenho que fazer diversas consultar em tabelas, às vezes dispostas em Sistemas Gerenciadores de Banco de Dados (SGBD) diferentes. Para este tipo de situação, o Eclipse SQL Explorer funciona muito bem, mas muitas vezes, são consultas simples e abrir este software ou qualquer outro para fazer a consulta pode ser desnecessário…

Então pensei em fazer algo simples, porém útil, um script em PHP que faça a consulta e apresente na saída padrão ( no terminal ).

Poderia ter sido usado qualquer outra linguagem de programação, usei o PHP por sua conexão com diferentes SGBD ser bem fácil e no momento estou mais familiarizado com sua sintaxe.

Preparando o Ambiente

Caso não tenha o PHP instalado ainda:

$ sudo apt-get install php5

Para este artigo, preparei o ambiente para realizar consultar no Postgres, MySQL e MS SQL Server.

Instale os módulos necessários para o PHP realizar a conexão:

$ sudo apt-get install php5-pgsql php5-mysql php5-sybase

Obs.: O php5-sybase é um módulo usado tanto para o Sybase como para o MS SQL Server.

Com a ajuda de um terminal embutido, como Guake, você nem vai precisar ir até um terminal usando o menu, basta usar o atalho configurado.

Ao final desse artigo teremos a possibilidade de fazer algo como:

Linux: Consultar SQL pelo terminal
Linux: Consultar SQL pelo terminal

Mão na massa ( O script PHP )

Arquivo de conexão

Para realizar a conexão com o SGBD fiz a classe DataBase ler um arquivo “.ini”, onde o mesmo é nomeado com o nome do SGBD seguido pelo nome da base de dados, e dentro dele seguem os dados do servidor (host), usuário, senha e opcionalmente a porta.

Exemplo de arquivo de configuração para conexão:

host    =
user    = postgres
pass     = gnuxx22l1n1

Classe de conexão

Seque o código da classe de conexão com os SGBD:

* classe DataBase
* Gerencia conexoes com bancos de dados através de arquivos de configuracao.
* Baseada em TConnection.class.php do livro: PHP Programando com Orientação a Objetos (Pablo Dall”Oglio)

class DataBase
public static $conn;

private function __construct() {}

* metodo open()
* recebe o nome do banco de dados e instancia o objeto PDO correspondente
* o arquivo segue o padrao: tipobanco_nomebase
private function open( $arquivo )
// verifica se existe o arquivo
if ( file_exists( “{$arquivo}.ini”) )
// le o INI e retorna um array
$nome = explode(‘_’, $arquivo );
$tipoBanco = $nome[0];
$nomeBase = $nome[1];
$db = parse_ini_file(“{$arquivo}.ini”);
// se nao existir, lanca um erro
throw new Exception(“Arquivo ‘$arquivo’ nao encontrado”);

// le as informacoes contidas no arquivo
$usuario = isset($db[‘user’]) ? $db[‘user’] : NULL;
$senha = isset($db[‘pass’]) ? $db[‘pass’] : NULL;
$host = isset($db[‘host’]) ? $db[‘host’] : NULL;
$porta = isset($db[‘port’]) ? $db[‘port’] : NULL;

// descobre qual o tipo (driver) de banco de dados a ser utilizado
switch ( $tipoBanco )
case ‘pgsql’:
$porta = $porta ? $porta : ‘5432’;
$conn = new PDO(“pgsql:dbname={$nomeBase}; user={$usuario}; password={$senha};
case ‘mysql’:
$porta = $porta ? $porta : ‘3306’;
$conn = new PDO(“mysql:host={$host};port={$porta};dbname={$nomeBase}”, $usuario, $senha);
case ‘mssql’:
$conn = new PDO(“dblib:host={$host};dbname={$nomeBase};charset=UTF-8”, $usuario, $senha);
// define para que o PDO lance excecoes na ocorrencia de erros
// retorna o objeto instanciado.
return $conn;

* Metodo que implementa o padrao Singleton
* O mesmo retorna a instancia de conexao de um banco caso ja exista
* Evitando a criacao de uma nova a cada solicitacao

public static function getConn( $nomeArquivo ) {
if ( ! isset( self::$conn[$nomeArquivo] ) ) {
self::$conn[$nomeArquivo] = DataBase::open( $nomeArquivo );
return self::$conn[$nomeArquivo];

Script de consulta (shellquery)

Agora o código do script PHP que realiza de fato a consulta no banco de dados, mediante parâmetros fornecidos via terminal.

# uso: shellquery tipoBanco_nomeBase “comandoSQL”
include_once “DataBase.class.php”;
$mostraNomeCampos = TRUE;
$banco = isset( $argv[1] ) ? $argv[1] : NULL;
$sql = isset( $argv[2] ) ? $argv[2] : NULL;
# se for passado um terceiro argumento, não exibe o nome dos campos
if ( isset( $argv[3] ) ) $mostraNomeCampos = FALSE;

if ( $banco == NULL || $sql == NULL ) {
echo “Sintaxe {$argv[0]} nomeArquivoConfiguracao comandoSQL\n”;

try {
$conn = DataBase::getConn( “$banco” );
$rs = $conn->query( $sql )->fetchAll();
} catch ( Exception $e ){
echo “Erro: {$e->getMessage()} :\nLinha: {$e->getLine()}\n”;

foreach ( $rs as $dados ) {
$ultimaCol = ( count( $dados ) / 2 ) – 1;

if ( $mostraNomeCampos == TRUE ) {
# obtem os nomes dos campos
$key = ( array_keys( $dados ) );
for ( $i=0; $i < count( $key ); $i++ ) {
if ( is_int( $key[$i] ) ) continue;
$campo[$x] = $key[$i];

# exibe os nomes dos campos
for ( $i=0; $i < $ultimaCol; $i++ ) {
echo “{$campo[$i]}|”;
echo “{$campo[$ultimaCol]}\n”;
$mostraNomeCampos = FALSE;

# exibe os dados
for ( $i=0; $i < $ultimaCol; $i++ ) {
echo “{$dados[$i]}|”;
echo “{$dados[$ultimaCol]}\n”;

Salve em um arquivo, como shellquery, dê permissão de execução:

$ chmod +x shellquery

E use à vontade.

Exemplo de uso

./shellquery pgsql_casa “SELECT * FROM disciplinas”



Bom, a saída deixei bem simples, exibindo os registros um por linha, separados por “|”, assim poderá ser usado a seu gosto, para:

– Quantos registros foram retornados?:

$ ./shellquery pgsql_casa “SELECT * FROM disciplinas” QUALQUERCOISA | wc -l



– Criar um arquivo CSV com separdor “;” no lugar de “|”:

$ ./shellquery pgsql_casa “SELECT * FROM disciplinas” | tr ‘|’ ‘;’ > resultado.csv

Arquivo resultado.csv aberto no libreoffice:

Linux: Consultar SQL pelo terminal

Enfim, podem ser feitas as infinidades de modificações que o GNU/Linux permite via shell.

Espero que ajude e facilite a vida de vocês, pra mim é uma mão na roda, uso todos os dias!

Etherwake + wake on coioti

 Clusterweb, Leitura Recomendada, Linux  Comentários desativados em Etherwake + wake on coioti
ago 092012

Apresentação e Mão na Massa

Olá amigos do VOL! Este é o meu primeiro artigo aqui no site e vou falar sobre uma tecnologia já antiga (1996) e que quase não se ouve falar dela, mas pode ser útil a muitos administradores de rede e usuários domésticos. Ela se chama WOL (Wake on Lan – Acordado pela rede).

– Resumo:

O conceito de Wake on Lan (WOL) foi desenvolvido pela AMD em 1996 com a finalidade de “acordar” computadores através de evento na placa de rede causado pelo envio de uma sequência especial de pacotes que tem como destino o endereço MAC da placa de rede.

– Pré-requisitos:

Para que esse procedimento seja realizado com sucesso, algumas configurações são necessárias. O suporte ao WOL deve vir disponibilizado na placa mãe ou na placa de rede caso essa seja off-board. Não é possível integrar o suporte ao WOL em um equipamento que não tenha esse suporte nativo de fábrica.

Para que seu equipamento mantenha a placa de rede ativa mesmo com o computador desligado é preciso que você esteja usando uma placa-mãe ATX 20 ou 24 pinos com uma fonte também ATX capaz de prover ao menos 900mA de corrente, para que a BIOS seja ativada mesmo sem o start do sistema (acredito que todas as placas ATX de hoje tenham suporte nativo ao WOL e todas as fontes do mercado sejam capazes de prover 900mA à placa-mãe).

Mão na massa

– Configurando a BIOS:

As configurações da BIOS para ativar o WOL dependem de cada fabricante, mas geralmente estão nas opções de energia da placa onde se pode habilitar o LAN Event ou PME Event como enable, disable ou last state.

  • Enable – WOL habilitado para ligar a máquina por eventos de rede;
  • Disable – WOL desabilitado;
  • Last state – WOL habilitado para ligar o computador caso esteja desligado e desligar caso esteja ligado. Mas para desligar o computador via WOL é preciso também algumas configurações no sistema operacional.
Linux: Etherwake + wake on coioti

Feito isso, salve as configurações e reinicie a máquina. Como as configurações são feitas diretamente na BIOS o WOL não depende de sistema operacional para ligar o computador mas depende do sistema caso deseje também poder desligar a maquina via WOL, nesse caso eu indico que procure como fazer essa configuração em seu sistema levando em conta que a gama de sistemas é grande demais para abordarmos todos neste tutorial.

– Configuração do sender:

Vamos chamar a máquina que vai enviar os pacotes de sender, ok? No meu caso eu uso Ubuntu mas o aplicativo que faz o envio dos pacotes é compatível com quase todas as distribuições que conheço. O pacote se chama Etherwake um aplicativo simples de usar e de instalar. Para quem usa Ubuntu:

# apt-get install etherwake

Em outros sistemas pode ser instalado através do source disponível em:

Descompacte o pacote usando o comando:

$ tar -zxvf etherwake_x.xx.orig.tar.gz

Entre no diretório descompactado:

$ cd etherwake_x.xx.orig

E compile o código:

# gcc ether-wake.c

Renomeie o executável:

# mv a.out etherwake

Feito isso é só mover para o diretório /bin para ficar disponível de qualquer lugar do sistema.

Usando o aplicativo Etherwake e wake on coioti

Para enviarmos o pacote do sender para o alvo precisamos saber o endereço MAC do alvo. Então, digamos que o meu alvo tem uma placa com MAC 70-71-BC-4E-3A-DB e esteja ligado na mesma rede que meu sender e também esteja ligado à rede elétrica.

Então o comando ficaria assim

# etherwake 70:71:BC:4E:3A:DB

Assim o comando envia a sequência de pacotes ao alvo e a placa de rede aciona o start da placa-mãe através do evento que recebeu em seu endereço MAC.

O pacote etherwake ainda tem a opção -b de broadcast que envia o pacote de start para todas as máquinas da rede:

# etherwake -b

Até aqui tudo bem, vou na máquina alvo, pego o MAC da placa e habilito na BIOS, isso é fácil, mais e se eu tiver um parque com 400 máquinas?

Como fazer para gerenciar uma lista com todos os MACs de todas as placas ?

Complicado né? Foi com esse tipo de problema que me deparei quando comecei a implementar essa tecnologia em alguns clientes.

Decorar o endereço MAC de cada máquina com 6 dígitos hexadecimais é muito complicado, uma planilha eletrônica ficaria muito extensa e mesmo com os filtros se tornaria chato ter que digitar o MAC para cada máquina que pretendo enviar o comando do sender.

– Interface Wake-on-coioti

Por isso resolvi criar um mini aplicativo em shell script de código aberto e licença GPL para simplificar a vida de quem deseja implementar esta solução em sua rede. Eu chamei o aplicativo de Wake-on-coioti e está disponível neste link:

Usando essa interface é possível dar um “apelido” às máquinas, como por exemplo a máquina do Diretor Geral da empresa que tem seu hostname como Dirgeral e endereço MAC 70-71-BC-4E-3A-DB. Assim, pode ser adicionada ao banco do aplicativo com o apelido de dirgeral e na hora de acordar a máquina usaremos o comando:

# wake -i dirgeral

Sem se importar qual é realmente o endereço MAC da placa de rede.

Além disso é possível mandar os pacotes para todas as máquinas cadastradas em seu banco usando o parâmetro -t e fazer backup do banco de máquinas cadastradas.

– Instalando o Wake-on-coioti

Depois de baixar o wake-on-coioti, basta descompactar:

$ tar -zxvf Wake_on_Coioti_Vx.x.tar.gz

Entrar no diretório que foi criado:

$ cd Wake_on_Coioti_Vx.x

Verifique as permissões do executável e se por acaso não estiver com permissão de execução use o comando abaixo para torná-lo um executável:

$ chmod -x

Dica: Leia o arquivo de README para obter todas as informações sobre a versão e particularidades do aplicativo.

Depois execute o instalador como root:

# ./

Depois de instalado o aplicativo fica disponível em /bin e sua lista em /opt/te.

Para chamar o aplicativo basta digitar como root o comando wake seguido do parâmetro que deseja e o alvo. Use o paramento –help para obter todas as opções do aplicativo.

Para cadastrar uma máquina use o comando:

# wake -c

Para dizer ao programa que você quer cadastrar um novo computador. Digite o apelido que você deseja dar a esse computador e caso ele ainda não esteja cadastrado ele vai pedir o endereço MAC da máquina que deve ser digitado usando “:” (dois pontos) para separar os caracteres hexadecimais.

Com a máquina cadastrada podemos usar o comando:

# wake -i <apelido>

Para iniciar um computador ou:

# wake -t

Para iniciar todos os computadores cadastrados.

Existem outros comandos que fazem backup, apagam, listam e etc.

Use o:

# wake –help

Para visualizar todas as opções ou leia o README.txt que acompanha o pacote.

Espero ter ajudado.

Tunando sistemas de arquivos para GNU/Linux

 Clusterweb, Leitura Recomendada, Linux  Comentários desativados em Tunando sistemas de arquivos para GNU/Linux
ago 092012

O que é “tunar” e o que é Sistemas de Arquivos

Antes de começar a tratar sobre o assunto de tunar o sistema de arquivos, precisamos saber o que é um sistema de arquivos.

Um sistema de arquivos é uma estrutura lógica que é utilizada para armazenar e organizar informações no sistema. Caso queira aprofundar seus conhecimentos e saber mais sobre sistema de arquivos, leia o artigo do link abaixo:

– O que é “tunar” um sistema de arquivos ?

Tunar um sistema de arquivos significa alterar características do mesmo, permitindo que F.S. seja personalizado para fins diversos.

Seja para uma otimização, deixando o sistema de arquivos mais rápido, ou para uma personalização mais cautelosa, permitindo que o mesmo fique mais consistente e robusto, para não corromper os dados caso aconteça algum erro ou falha.

O artigo irá abordar as práticas de tunar os sistema de arquivos mais usados no pelas distribuições GNU/Linux deixando os mesmos mais velozes, leves e/ou mais consistentes.

No final do artigo irei mostrar gráficos que representam um teste de desempenho de cada um após a personalização para melhor desempenho, trata- se de uma benchmark (teste de desempenho) básico para dar uma ideia da velocidade que o mesmo pode obter em determinadas tarefas.


Nas páginas seguintes, toda a personalização é feita pela linha de comando, então, se você não está seguro em fazer as alterações abordadas nas próximas páginas, ou não gosta de linha de comando, pare por aqui mesmo, caso queira fazer as alterações e/ou fazer uma boa leitura, continue.

Algumas características serão aplicadas antes da instalação da distribuição que será usada, isto será feito com o propósito de obter um melhor funcionamento desde o inicio. Essa é a melhor opção.

Os sistemas de arquivos foram tunados na distro Debian GNU/Linux, versão 6.0.5.

A máquina usada possui um processador Intel® Core™2 Duo, quatro gigabytes de espaço na RAM e um disco SATA 3.0 de 7200 RPMs.

Antes de começar a colocar em prática todo o trabalho, tenha em mãos um LiveCD do Ubuntu, Linux Mint ou Parted Magic, pois será necessário.

Todo o trabalho de “tunar” apresentando nas páginas seguintes foi testado.

Caso sinta-se encorajado a fazer o trabalho, monte seu ambiente de testes para ter certeza de que as alterações serão úteis para uso em produção, para só então, aplicá-las em definitivo.

Opções de montagem e vantagens e desvantagens de usar journal externo

Nesta parte do artigo, dedico a esclarecer qual é a finalidade principal de cada opção de montagem que podem ser usadas para tunar os sistemas de arquivos abordados no artigo, podendo incluir as mesmas no “/etc/fstab”, além de explicar a vantagem de usar um journal externo.


  • atime: Opção usada para atualizar o tempo de acesso aos arquivos, este tipo de informação é armazenada nos inodes dos arquivos. Por exemplo, quando você clica com o botão direito e vai em ‘Propriedades’ do arquivo, lá tem o tempo de acesso.
  • noatime: Esta opção faz com que o sistema de arquivos não atualize o tempo de acesso aos arquivos. Caso habilite este comportamento no F.S., não conseguirá obter o tempo preciso do último acesso feito aos arquivos gravados.
  • async: Opção usada para que o sistema de arquivos faça as operações de forma assíncrona. A sincronização de dados (input/output) será feita depois, e não na hora da transferência de dados.

    Por exemplo: Se você está gravando dados no seu disco externo, os dados somente serão gravados por completo, no momento que o sistema de arquivos for desmontado.

    Caso esqueça de desmontar o dispositivo, removendo o mesmo sem desmontar da forma correta, o risco de perder seus dados é alto, este é o comportamento padrão dos sistemas de arquivos usados no GNU/Linux.

  • sync: Opção usada para que o sistema de arquivos trabalhe de forma síncrona, fazendo a sincronização de dados (input/output) no momento da transferência de dados.

    Por exemplo: Você vai gravar alguns arquivos no pendrive com esta opção habilitada no sistema de arquivos do pendrive, toda a gravação dos dados será feita na hora e não no momento de desmontar o sistema de arquivos.

    Este não é o comportamento padrão dos sistemas de arquivos usados no GNU/Linux. Caso habilite esse comportamento, a transferência de dados ficará bem lenta, principalmente em transferência de dados grandes.

  • diratime: Esta opção é similar ao atime, mas ao invés de atualizar o tempo de acesso aos arquivos, atualiza o tempo de acesso aos diretórios.
  • nodiratime: Ao contrário da opção diratime, está opção não atualiza o tempo de acesso ao diretórios, pode ser usada para ter um pouco mais de desempenho, já que toda ação de acesso não será armazenada nos inodes.
  • dirsync: Similar a opção sync, mas ao invés da sincronização de dados (input/outpu) serem feitas de forma síncrona nos arquivos, serão feitas nos diretórios.
  • relatime: Opção usada para atualizar o tempo de acesso aos arquivos referentes à modificação/alteração nos arquivos.

    Caso habilite este comportamento no seu sistema de arquivos, o tempo de acesso aos arquivos só será atualizado caso o tempo relativo à modificação for mais atual do que o antigo, ou seja, só será atualizado caso haja alguma modificação/alteração nos arquivos, e não um simples acesso. Esta opção é similar ao noatime. Caso deixe a mesma habilitada terá um ganho de desempenho.

  • norelatime: Esta opção desabilita o recurso relatime, pois não vai atualizar nos inodes o tempo de acesso relativo à modificação e/ou alteração.
  • barrier: Este comportamento chama-se barreira, e é usado em conjunto com journal.

    Para entender melhor esta opção de comportamento do sistema de arquivos, temos que ter em mente o seguinte: toda alteração no sistema de arquivos que usa journaling, armazena primeiro os registros de alterações de sua estrutura, seja um arquivo ou diretório, no journal, para posteriormente fazer a gravação efetiva dos dados.

    Porém, se os blocos de dados e/ou registros de alteração de dados que serão feitos de forma efetiva não forem escritos antes no journal, seu sistema e arquivos poderão comprometer as informações armazenadas na sua estrutura.

    Habilitando o barrier, evita-se a gravação desordenada, evitando que os dados fiquem corrompidos no sistema, pois os blocos de dados e/ou os registros são primeiro armazenados no journal para posteriormente, serem gravados efetivamente no sistema.

    Quando este comportamento é habilitado, é garantido que o F.S. tenha sua consistência mantida, mas em compensação, terá uma perda de desempenho. Caso deixe desabilitada, ganhará desempenho, porém, tenha certeza que o mesmo poderá ficar corrompido de forma mais fácil do que quando este comportamento está habilitado, pois nenhum sistema de arquivos é anti falhas, e sim tem uma tolerância à falhas.

    Para habilitar, coloque no “/etc/fstab barrier=1”, ou “barrier=flush” (vai depender do F.S. usado). Caso queira deixar desabilitada, coloque no “/etc/fstab barrier=0”, ou “barrier=none” (relativo ao F.S. usado).

Vantagens de se usar Journal Externo

Antes de falar sobre as vantagens, primeiro vem a definição de journal, que é uma área reservada para armazenamento de registros/log de ações feitas nos dados, tais como: leitura/alteração e ou gravação de novos dados na estrutura do F.S.

Para uma melhor compreensão, acesse o artigo Sistemas de arquivos para GNU/Linux, página 2.

O Journal do sistema de arquivos é a parte mais acessada do seu disco rígido. Seja para qualquer ação que você faça o Journal é acessado, ou seja, tanto nas operações de leitura como de escrita.

Desta forma, o disco precisa gravar os dados no journal (log) e no sistema de arquivos. Logo, nota-se que o disco tem que fazer dois movimentos: um para gravação no journal e outro no F.S. em si, além de ter um journal com tamanho limitado.

Isto pode influenciar no desempenho, já que o log fica limitado pelo tamanho e também o Seek time é maior.

Seek time é o tempo gasto para movimentar a cabeça do disco para ler e escrever no disco até a trilha/setor desejado.

No entanto, ao colocar o journal (área de log) em outro disco, tem-se um ganho quanto ao seek time, pois o mesmo disco que armazena o sistema, não precisará fazer dois movimentos (um no sistema de arquivos e outro journal).

Com isso, ganha-se velocidade na leitura/escrita de dados, além de poder deixar o Journal com um tamanho maior, permitindo armazenar mais dados (se necessário) de uma vez. Com isso, o ganho de desempenho é garantido.

Mesmo colocando o journal em outra partição do mesmo disco onde está o sistema, tem-se um ganho de desempenho. Não igual se comparado a colocar em outro disco, mas ganha.

Lembre-se que, para cada partição que usará com journal externo, deverá ter uma partição dedicada para armazenar o journal. Se pretende colocar o diretório “/” e “/home” em partições separadas e usar a área de registro para ambas partições com localização externa, então dedique duas partições para para receber o log, cada partição para um diretório.

Desvantagem de usar Journal Externo

Se o disco rígido em que está o journal externo for acidentalmente desligado, você não poderá iniciar o seu sistema, mas nenhum dado estará perdido!

Nem mesmo dando boot pelo LiveCD, você terá acesso aos seus dados. Você precisará do Journal externo para ler os seus dados. Basta então, religar o disco rígido em questão, na mesma ordem em que tudo foi configurado, que tudo volta ao normal.

Se o disco rígido em que está o journal externo chegou ao fim de sua vida útil, ou está com defeitos irreparáveis, você não poderá acessar os seus dados e o que estiver fazendo no momento do problema pode estar perdido.

Aí você pode perguntar-se: Como então eu volto a ter acesso aos meus dados?

Resposta: Substitua o disco onde estava o journal da partição, aplique o sistema de arquivos em uma nova partição, e execute os comandos que serão usados nas páginas seguintes para preparar o HD para receber o journal externo, e anexar o journal do sistema no novo HD. Depois reinicie a máquina e use o sistema.

* NOTA: Nem todos os sistemas de arquivos abordados neste artigo poderão migrar o seu journal externo para outro dispositivo, sem que o dispositivo anterior (dispositivo que continha o journal) esteja presente e/ou sem formatar a partição que contém o sistema.

Independentemente do seu sistema de arquivos e das modificações que você possa fazer no seu sistema, sempre faça backup antes de fazer as alterações instruídas nas páginas seguintes.

Tunando o sistema de arquivos ReiserFS

Serão abordadas duas formas de tunar o sistema de arquivos para um melhor desempenho e para torná-lo mais robusto.

Uma das formas que vou utilizar é o journal externo, ou seja, o journal do sistema de arquivos ReiserFS vai estar em outra partição. Porém, você poderá também colocá-lo em uma partição de outro disco.

E a segunda forma vai ser com o journal interno, ou seja, na partição onde está armazenado o sistema.

Para aplicar o journal externo, particione o disco conforme sua necessidade. Contudo, usarei para explicar o seguinte particionamento do disco para instalar o S.O.:

  • Partição: /dev/sda1 – Diretório root “/”;
  • Partição: /dev/sda5 – Swap;
  • Partição: /dev/sda6 – Partição usada para armazenar o journal externo da partição /dev/sda1.

NOTA: Este sistema de particionamento é apenas um exemplo para fins didáticos,não é obrigatório. De forma que, não é preciso usar o journal externo na partição onde ficar root “/”, então, você pode particionar da forma que melhor atende às suas necessidades, adicionando até mais partições se for necessário.

Não vou abordar como particionar usando o fdisk e nem o GParted, pois existem muitos materiais que abordam o uso dessas ferramentas.

Tunando o ReiserFS usando journal externo

Antes de começar a parte prática, tenha em mãos um LiveCD do Ubuntu, Linux Mint e ou Parted Magic, para aplicar as alterações. Caso não tenha no LiveCD (ou no sistema que está usando para particionar e aplicar o sistema de arquivos) suporte a ReiserFS, então instale o pacote “reiserfsprogs”.

Supondo que você já particionou o disco que armazenará o S.O., é hora de aplicar o sistema de arquivos ReiserFS. Mas antes, desmonte as partições que usará no procedimento de aplicação de F.S.

1. Aplique o sistemas de arquivos em “/dev/sda1” com journal externo. O journal da partição “/dev/sda1” ficará no dispositivo “/dev/sda6”, que será a partição raiz e que abrigará toda a estrutura de diretórios.

# mkreiserfs -j /dev/sda6 /dev/sda1

No comando anterior, não especifiquei o tamanho do journal na partição, então, o tamanho assumido por padrão, é 8193 blocos. Caso queira colocar um tamanho de journal acima do tamanho padrão, use junto ao comando mkreiserfs a opção “-s”, ou “–journal-size”.

Sabendo que o tamanho máximo do journal é de 32749 para partições com blocos de 4 kbytes.

Então, com a opção de tamanho ficaria assim:

# mkreiserfs -s 8193 -t 1024 -j /dev/sda6 /dev/sda1

Onde “-s” especifica o tamanho do journal, e “-t” especifica o máximo de blocos que podem ser transferidos para o journal de uma vez. 1024 é o máximo, não consegui fazer com valor superior, e o valor deve ser menor do que metade do tamanho do journal.

Após aplicar o sistema de arquivos, veja como fica a particionamento no GParted na imagem abaixo:

2. Instalação do S.O. Debian GNU/Linux 6.0.5

NOTA: Não tratarei a instalação por completo, apenas partes importantes para finalizar a mesma.

2.1. Na primeira tela de instalação, escolha a opção “Advanced Options” e em seguida “Graphical Expert Install”. Depois carregue os módulos do sistema de arquivos ReiserFS:

2.2. Em particionamento do disco, escolha a opção “Manual” e deixe a partição Raiz conforme mostrado na imagem abaixo, ou seja, deixe marcado para usar o sistema de arquivos ReiserFS e adicione o ponto de montagem como root “/”, mas marque para não formatar:

Ao final, o particionamento ficará assim, depois aplique as alterações feitas:

Após a instalação do S.O com journal externo, você terá um sistema ReiserFS com mais velocidade, porém, em um desktop que é usado para acesso à Internet e/ou tarefas básicas, não nota-se diferença a princípio. Ou seja, só repara-se diferença quando está fazendo operações em massa, aí sim notará diferença.

Agora, edite e acrescente algumas opções de montagem para alterar o comportamento do ReiserFS no arquivo “/etc/fstab”:

# vim /etc/fstab

/dev/sda1     /     reiserfs    notail,rw,data=writeback,relatim e    0    1

* notail: Por padrão, esta opção já veio ativada após a instalação, mas caso não esteja habilitada, coloque a mesma no fstab. Esta opção muda o comportamento do sistema de arquivos ReiserFS, fazendo com que o mesmo ganhe um pouco de desempenho.

Explicando bem o que esta opção notail faz:

Toda informação que é gravada no disco, é armazenada em blocos de dados, cada bloco possui um espaço para alocar informações que é determinado durante a aplicação do sistema de arquivos.

Desta forma, se um arquivo possuir 17 kbytes de tamanho e for armazenado em um sistema de arquivos cujo tamanho do bloco é 4 kbytes, o arquivo iria ocupar cinco blocos de 4 kbytes. Assim, o último bloco ficaria com 3 kbytes de espaço sobrando sem poder serem usados.

Mas, com o recurso “tail packing”, este espaço restante livre mencionado na explicação anterior, pode ser preenchido com os restos de dados de outros arquivos.

Isto pode causar fragmentação, mas como o sistema de arquivos está com a opção “notail” habilitada, a fragmentação é praticamente nula, e a velocidade de acesso aos dados torna-se rápida, já que os “restos” de dados não serão armazenados em blocos com espaços que estão sobrando. Mas em compensação, haverá perda de espaço.

* data=writeback: Esta opção faz com que o sistema de arquivos ReiserFS atue no modo de operação writeback, gravando no journal apenas os metadados a cada ação nos arquivos, sem forçar a gravação dos metadados no sistema de arquivos após a gravação no journal. Isto garante maior desempenho mas poderá perder dados com maior facilidade.

Uma outra forma de melhorar ainda mais o desempenho, porém perdendo algumas informações (como data de acesso a arquivos e diretórios), seria adicionar no “/etc/fstab”:

/dev/sda1     /     reiserfs    notail,rw,data=writeback,noatim e,nodiratime    0    1

As outras opções já foram abordadas na página anterior.

Lembre-se que, adicionando a opção de montagem ‘data=writeback’, o risco de perder dados é maior, porém, como o journal está externo já existe um ganho de desempenho.

Podemos adicionar, ou retirar, algumas opções para mudar o comportamento do sistema de arquivos, fazendo o mesmo ficar mais consistente e/ou continuar rápido, mas mantendo um bom nível de consistência.

Vejam só como ficaria as opções de montagem no “/etc/fstab”, deixando o sistema de arquivo num misto de consistência e velocidade com journal externo:

/dev/sda1     /     reiserfs    notail,rw,relatime,barrier=flush& nbsp;   0    1

Ou, deixa manter os dados com o máximo de segurança sem importar-se com a velocidade. Veja o exemplo abaixo adicionado no “/etc/fstab”:

/dev/sda1     /     reiserfs    notail,rw,sync,barrier=flush  ;   0    1

Após aplicar as alterações, notará que vai ficar lento, principalmente em atividades de gravação e transferência de dados.

É importante deixar bem claro que, caso o dispositivo que contém o journal externo do F.S. do sistema chegue ao fim de sua vida útil, ou seja danificado. O seu sistema não poderá mais ser acessado enquanto não houver um novo journal externo.

Para resolver isso, execute os comandos a seguir com o sistema de arquivo do sistema desmontado:

# reiserfstune -f –no-journal-available –journal-new-device /dev/sdb2 /dev/sda1

No comando acima, estou supondo que o novo dispositivo que conterá o journal do sistema é “/dev/sdb2”, e o dispositivo que contém o sistema é “/dev/sda1”.

As opções:

  • journal-new-device: indica a nova localização do journal do F.S. do sistema.
  • no-journal-available: indica que o dispositivo “/dev/sda1”, ou seja, o dispositivo que contém o sistema, não tem journal.

Você pode ainda mudar o tamanho do journal com a opção “-s”, junto ao comando reiserfstune.

Mas tenha em mente que foi criado um novo journal e conteúdo, do antigo foi perdido, de maneira que se antigo log contém alguma informação para ser recuperada, a mesma foi perdida com a criação do novo journal.

Tunando o ReiserFS usando journal interno

Para tunar o sistema de arquivos com journal interno, o procedimento é mais fácil, pois não precisa fazer alterações especificas antes e durante a instalação do S.O., basta apenas manipular as informações dentro o “/etc/fstab”, pois assim é mais fácil.

As opções de montagem já usadas anteriormente podem ser usadas também com journal interno. E estarei usando o mesmo esquema de particionamento já visto com journal externo.

Por exemplo, para um maior desempenho mesmo com o journal interno, poderíamos fazer o ReiserFS trabalhar bem rápido, adicionando as seguintes opções no “/etc/fstab”:

/dev/sda1     /     reiserfs    notail,rw,data=writeback,relatim e    0    1

Ou, deixar o ReiserFS com mais ganho de desempenho, adicionando as seguintes linhas no “/etc/fstab”:

/dev/sda1     /     reiserfs    notail,rw,data=writeback,noatim e,nodiratime    0    1

Ou, tunar o ReiserFS deixando-o mais robusto, porém perdendo velocidade, para manter os dados de sua estrutura:

/dev/sda1     /     reiserfs    notail,rw,sync,barrier=flush  ;   0    1

Lembre-se que todas estas personalizações tem que ser utilizadas para bons resultados junto às características positivas do ReiserFS.

Exemplo: O ReiserFS trabalha melhor com arquivos pequenos.

Tunando o sistema de arquivos XFS

Antes de tunar o XFS, tenha em mente que ele foi desenvolvido para ser usado em sistemas grandes e uma de suas características positivas é trabalhar muito bem com arquivos grandes. Sendo que uma característica negativa, é não ter um bom desempenho com arquivos pequenos.

Também é necessário explicar como sua estrutura está organizada para um melhor entendimento. O XFS é dividido em três partes, cada parte fica localizada uma seção.

As seções são:

  • A seção de dados: Contém todos os metadados do sistema de arquivos (inodes, diretórios), bem como os dados do usuário, como arquivos e até mesmo o aquivo de log, caso o journal seja interno. A seção de dados é dividido em um número de grupos de alocação.

    O número e tamanho dos grupos de alocação são determinados pelo comando mkfs.xfs. O número de grupos de alocação controla a quantidade de dados que podem ser transferidos paralelamente.

    Se não tiver uma máquina “potente” (com uma boa quantidade de memória disponível e processador com poder de processamento bom) o número de grupos de alocação não deve ser muito alto, pois isto pode causar sobrecarga no processador. Caso contrário, aumente este número pois pode aumentar o desempenho.

  • A seção de log: É usada para armazenar as alterações de metadados do sistema de arquivos enquanto o mesmo está sendo executado, até que as alterações sejam feitas pela a seção de dados.

    Este é escrito sequencialmente durante as operações normais (enquanto o sistema está em uso) e lido apenas durante a montagem. Ao montar um sistema de arquivos, depois de um acidente, o log é lido para operações completas que estavam em curso no momento do acidente, e restaura a estrutura até onde é possível.

  • A seção de tempo real: É usada para armazenar os dados do sistema de arquivos em tempo real. Antes que qualquer dado seja escrito definitivamente no F.S.

Assim como nos outros sistema de arquivos, vou apresentar duas formas de tunar: uma para desempenho e outra para maior consistência, tanto usando journal externo quanto journal interno.

Apresentando particionamento usado para aplicar as alterações:

  • Partição: /dev/sda1 – Diretório root “/”;
  • Partição: /dev/sda2 – Diretório home “/home”;
  • Partição: /dev/sda5 – Swap;
  • Partição: /dev/sdb2 – Partição usada para armazenar o journal externo da partição /dev/sda2.

NOTA: Este é apenas um exemplo de particionamento para explicar como fazer o trabalho, ou seja, apenas para fins didáticos. O leitor pode tanto seguir este esquema como pode personalizar da forma que quiser.

Preferi usar este particionamento, pois diretórios como “/home”, e outros que podem ser criados, podem armazenar uma grande quantidade de arquivos grandes, e XFS tem um bom desempenho com arquivos grandes.

É importante deixar bem claro também que, o sistema de arquivos XFS quando usa journal externo não tem outra forma de migrar seu journal de uma partição de um dispositivo para outra partição sem perda de dados.

Para fazer tal migração, é necessário aplicar o F.S. na partição onde está instalado o sistema que foi configurado para deixar o journal em outro dispositivo. Pelo menos, não encontrei nenhuma forma que não seja usando o comando mkfs.xfs apresentado no decorrer desta página.

Isto quer dizer que, caso o dispositivo que contém o journal fique defeituoso, ou chegue ao fim de sua vida útil, não terá como acessar os dados do sistema que tem o XFS usando journal externo, nem usando um LiveCD.

A única forma é criar um novo journal usando o comando mkfs.xfs, porém, este comando irá aplicar um novo sistema de arquivos ao sistema que não tem mais journal apagando toda informação contida nele.

Então, se quer usar seu sistema usando o F.S. XFS, a melhor opção é com journal interno, mas caso deseja usar o sistema com XFS e journal externo, é melhor fazer backup de seus dados.

Tunando o XFS usando journal externo

Não será abordado como particionar e nem a instalação passo a passo, apenas detalhes importantes. Mas o esquema de particionamento usado será o mesmo especificado acima. Então, vamos à prática:

1. Instalação do S.O. GNU/Linux Debian 6.0.5. Na primeira tela de instalação, escolha a opção “Advanced options” e em seguida “Graphical Expert Install”:

2. Depois, prossiga com a instalação normalmente e particione. Veja como ficou o particionamento usado no artigo:

3. Após instalar o sistema, o GRUB ou LILO, é hora de fazer as partes mais importantes que merecem atenção total.

* NÃO finalize a instalação e escolha a opção de “Executar um shell” para entrar na linha de comando:

3.1. Na linha de comando, veja que o dispositivo que estou usando no artigo e que armazena “/home” é “/dev/sda2”, então, desmonte o mesmo. Caso use outro, troque conforme sua necessidade:

# mount
# umount /dev/sda2

3.2. Agora vamos aplicar o sistema de arquivos XFS com Journal externo armazenado na partição “/dev/sdb2”:

# mkfs.xfs /dev/sdb2
# mkfs.xfs -f -l logdev=/dev/sdb2,size=1g -d agcount=4 -i maxpct=5 /dev/sda2


  • -f : Quando está opção é usada, indica que já existe um sistema de arquivos XFS no dispositivo que irá ser formatado, o F.S. existente será sobrescrito.
  • -l : Seção de opções de log. Estas opções especificam a localização, tamanho e outros parâmetros da seção de log do sistema de arquivos.

    Existem vários parâmetros nesta seção, mas explicarei os usados:

    • logdev : Este parâmetro indica o dispositivo que armazenará o log. Ele é usado quando se deseja usar o journal externo em outra partição do mesmo disco ou de outro disco. No comando anterior, armazenei o journal no dispositivo “/dev/sdb2”.
    • size : Parâmetro usado para especificar o tamanho do log. No comando anterior, usei um gigabyte de tamanho para o journal (o mínimo é 512 blocos).
  • -d : Seção de opções de dados. Estas opções especificam a localização, tamanho e outros parâmetros da seção de dados do sistema de arquivos.

    O parâmetro usado nesta seção foi:

    • agcount : Este parâmetro especifica o número de grupos de alocação. Como já foi explicado anteriormente, o XFS divide o a sua estrutura lógica de arquivos em grupos de alocação para aumentar o desempenho com leituras em paralelo dos blocos e inodes.

      Mas cuidado ao escolher o número de grupos de alocação usados, pois colocando um número muito alto e/ou baixo demais poderá perder desempenho de acordo com a carga do sistema e do desempenho da máquina.

      O comando mkfs.xfs calcula o número de ‘agcount’ de acordo com o tamanho do dispositivo a ser formatado. Seus valores variam normalmente entre 4, 8, 16 e 32. Você também pode colocar outros valores como 2, 6 e 56, ou até mesmo números maiores.

      Recomendo testar em uma máquina separada, para depois ser colocado em produção a melhor configuração que atendeu às necessidades. Na formatação usada no artigo usei o valor de “4”, mas usei o mesmo pois o espaço da partição em disco é pequeno.

  • -i: Parâmetro usado para especificar opções de inodes. Esta opção especifica o tamanho do inode do sistema de arquivos, e outros parâmetros de alocação de inode.
    • maxpct : Este parâmetro especifica a porcentagem máxima que o sistema de arquivos pode alocar com inodes. Os valores padrões são: 25% para um sistema de arquivos com menos de 1TB, 5% para os menores que 50TB, e 1% para os acima dos 50TB.

      Estes parâmetros influenciam no espaço em disco, podendo fazer você desperdiçar espaço em disco. Com isso, vocês podem notar que o XFS foi pensado para ser grande.

3.3. Adicione o novo “UUID” da partição “/dev/sda2” que armazena o home dos usuários do sistema instalado no final do arquivo “/target/etc/fstab”. Este arquivo é o “/etc/fstab” do Debian instalado.

E em seguida, edite o fstab com as opções de montagem a seguir, trocando o “UUID” correspondente à partição Home pelo que foi enviado para o fim do arquivo.

* NOTA: Troque o “UUID” informado pelo “UUID” da partição do disco usado.

# blkid /dev/sdb2 >> /target/etc/fstab
# nano /target/etc/fstab

UUID=68f06b5-1e92-4348-9a7f- 77c47801f6b     /home    xfs    rw,logdev=/dev/sdb2,relatime,allocsi ze=64m   0   2

Depois de aplicar as alterações, salve-as.

As principais opções adicionadas ao fstab do sistema recém instalado:

  • logdev : Informa aonde se encontra o journal externo. Se esta opção não for especificada no fstab, o sistema de arquivos ficará impossibilitado de ser montado.
  • allocsize: Este parâmetro especifica o tamanho final da pré alocação do Buffer de I/O. Seu tamanho varia de 64Kib a 1Gib.

    Esta opção ajuda a diminuir a fragmentação do disco e aumenta a velocidade de transferência de arquivos grandes. Se está usando o sistema de arquivos apenas para armazenar arquivos grandes, use 512 MB ou mais.

    Na prática, quanto maior esse número, melhor a taxa de transferência, mas o sistema pode ficar mais preso à processos ao transferir muitos dados.

3.4. Monte a partição novamente e volte para a tela de opções, finalize a instalação escolhendo a opção: Finalizar a Instalação

# mount -t xfs /dev/sda2 /target/home -o logdev=/dev/sdb2,rw
# exit

Depois da instalação do S.O e iniciar o mesmo, ainda pode acrescentar alguns comportamentos para melhorar o desempenho:

UUID=68f06b5-1e92-4348-9a7f-77c47801f6b /home xfs rw,logdev=/dev/sdb2,relatime,allocsize=64m,delaylog,logbsize=128    0    2

* Note que, com algumas dessas opções, poderá perder dados em caso de erros que aconteçam no sistema.

  • delaylog : Este parâmetro atrasa a gravação das informações no journal do XFS o máximo possível. O delaylog acelera muito o XFS, mas aumenta o risco de perda de dados no caso de uma queda de energia ou travamento do sistema.

    O journal não está sendo desativado, apenas a gravação está sendo atrasada. Esta opção pode não funcionar em versões antigas do kernel ou do XFS, por isso, tenha um kernel sempre atual para usar esta opção junto com XFS, como o kernel 2.6.x ou 3.x.

  • logbsize : Parâmetro que especifica o tamanho de cada buffer na memória, podendo ser especificado em Bytes ou Kilobytes, sendo que o padrão é 32k nas versões mais recentes do kernel.

    Podendo aumentar este valor para 64k, 128k até o máximo de 256k. O logbsize pode ajudar muito o XFS a lidar com arquivos pequenos e aumenta o consumo de RAM. Usei o valor de 128 mas caso tenha um sistema maior use 256.

Mas, se mesmo assim você não está satisfeito e quer mais velocidade sem se importar com perda de dados, faça:

UUID=68f06b5-1e92-4348-9a7f-77c47801f6b /home xfs
rw,logdev=/dev/sdb2,norelatime,allocsize=64m,delaylog,logbsize=128,noatime,nodiratime,nobarrier    0    ; 2

Caso queira mais segurança, para seus dados sacrificando um pouco do desempenho, poderá usar em seu fstab as opções abaixo:

UUID=68f06b5-1e92-4348-9a7f-77c47801f6b /home xfs rw,logdev=/dev/sdb2,allocsize=64m,logbsize=128   0    2

Ou, se quer sacrificar mesmo o desempenho e manter seus dados com menor risco possível de perda de informações, use:

UUID=68f06b5-1e92-4348-9a7f-77c47801f6b /home xfs rw,logdev=/dev/sdb2,allocsize=64m,sync    0    2

Tunando o XFS usando journal interno

Para tunar o XFS com journal interno, utilizarei o seguinte esquema de particionamento:

  • Partição: /dev/sda1 – Diretório root “/”;
  • Partição: /dev/sda2 – Diretório home “/home”;
  • Partição: /dev/sda5 – Swap.

Seguindo o esquema de particionamento apresentando, execute os seguintes comandos para deixar ambas as partições com um tamanho maior do journal interno:

# mkfs.xfs -f -l internal,size=128m -d agcount=4 -i maxpct=5 /dev/sda1
# mkfs.xfs -f -l internal,size=128m -d agcount=4 -i maxpct=5 /dev/sda2

Veja como ficou o particionamento após aplicação dos comandos:

As opções usadas já foram abordadas antes, porém tenho que informar que o log ficou na mesma partição do diretório “/home” do sistema.

Lembre-se que o “-l” indica a seção de log. Onde o journal está localizado e o tamanho do mesmo, além de outras informações.

  • internal: Indica que o journal é interno. Enquanto que a opção “size” informa o tamanho do mesmo. Usei 128 megabytes pois não posso exagerar quando o journal está localizado na mesmo volume, pois ocupará muito espaço, podendo deixar o sistema muito lento. Não darei explicações das outras opções usadas, pois as mesmas já foram explicadas anteriormente.

Em seguida, instale o sistema operacional. Como explicado desde o início, estou usando o Debian 6.0.5 para aplicar as alterações.

1. Na primeira tela de instalação, escolha a opção “Advanced options” e em seguida, “Graphical Expert Install”

2. Como não mostrarei detalhes da instalação, o próximo passo é o particionamento do sistema. Então, prossiga com a instalação até chegar ao particionamento.

Escolha a opção “Manual” e deixe a partição raiz conforme mostrado na imagem abaixo, ou seja, deixe marcado para usar o sistema de arquivos XFS em ambas as partições, e adicione o ponto de montagem para root “/” e home “/home”, mas marque para não formatar:

Particionamento de ‘/dev/sda1″, partição com diretório root “/”:

Particionamento de “/dev/sda2”, partição com diretório home “/home”:

Veja na imagem abaixo, como ficou o particionamento final:

Conclua a instalação e em seguida, inclua as seguintes alterações no arquivo “/etc/fstab” do sistema:

UUID=72fe0d80-ee18-4e8f-84da-8e5700d38c66 /     xfs rw,relatime,attr2,delaylog,nobarrier,logbsize=256    0    1

UUID=df045744-39ef-491c-85f6-13082112dce7 /home xfs rw,relatime,attr2,delaylog,nobarrier,logbsize=256    0    2

Usando estas opções, o XFS terá um bom desempenho, já que o tamanho do journal, mesmo localizado internamente é grande. Mas existe risco de perda de dados. Mas, se não importa-se com isso e quer mais desempenho, coloque no seu fstab as seguintes opções:

UUID=72fe0d80-ee18-4e8f-84da-8e5700d38c66 /     xfs rw,norelatime,allocsize=64m,delaylog,logbsize=128,noatime,nodiratime,nobarrier  0  1

UUID=df045744-39ef-491c-85f6-13082112dce7 /home xfs rw,norelatime,allocsize=64m,delaylog,logbsize=128,noatime,nodiratime,nobarrier  0  2

Desta forma, o desempenho irá aumentar, mas o risco de perda de dados também aumentará.

Veja que de acordo com as opções usadas, o XFS irá mudar seu comportamento padrão e não irá atualizar nos inodes a data do último acesso em arquivos e diretórios, assim como atrasar a gravação dos dados no journal.

Veja uma forma de colocar um meio termo, entre segurança dos dados e desempenho:

UUID=72fe0d80-ee18-4e8f-84da-8e5700d38c66 /     xfs rw,allocsize=64m,logbsize=128  0  1

UUID=df045744-39ef-491c-85f6-13082112dce7 /home xfs rw,allocsize=64m,logbsize=128  0  2

Tunando o sistema de arquivos JFS

Para tunar o JFS, usarei o esquema de particionamento descrito abaixo. Porém, assim como nos outros sistemas de arquivos, farei uso do journal externo e interno para fazer este trabalho.

Apresentando particionamento usado para aplicar as alterações:

  • Partição: /dev/sda1 – Diretório root “/”;
  • Partição: /dev/sda2 – Diretório home “/home”;
  • Partição: /dev/sda5 – Swap;
  • Partição: /dev/sdb1 – Partição usada para armazenar o journal externo da partição /dev/sda1;
  • Partição: /dev/sdb2 – Partição usada para armazenar o journal externo da partição /dev/sda2.

Tunando usando o journal externo

Diferente do que foi feito anteriormente, vou mostrar duas formas de deixar o sistema instalado com journal externo. Primeiro, vou mostrar como fazer antes da instalação do sistema.

Para isso, dê boot pelo LiveCD, como o Parted Magic ou outro, e execute os comandos a seguir. Se no sistema que está usando para executar as tarefas não estiver instalado os comandos, será necessário instalar o pacote “jfsutils”.

1. Prepare as partições que armazenarão os logs com os comandos abaixo, desta forma, estamos dizendo que as partições “/dev/sdb1” e “/dev/sdb2”, são partições de journal externo:

# jfs_mkfs -J journal_dev /dev/sdb1
# jfs_mkfs -J journal_dev /dev/sdb2

2. Em seguida, aplique o sistema de arquivos JFS nas partições onde será armazenado o sistema, indicando que os dispositivos que contém os journals externos são “/dev/sdb1” e “/dev/sdb2”.

# jfs_mkfs -J device=/dev/sdb1 /dev/sda1
# jfs_mkfs -J device=/dev/sdb2 /dev/sda2

Veja como ficaram as partições que receberam o journal:

3. Na instalação do S.O., apenas abordarei as partes importantes que merecem ser destacadas.

3.1. Escolha a opção na tela de boot “Advanced Options” e em seguida “Graphical Expert Install”

3.2. No particionamento, escolha a opção “Manual” para fazer as alterações, e em seguida, escolha as partições onde irá instalar o sistema. Coloque o ponto de montagem para “/dev/sda1” e “/dev/sda2” e escolha o sistema de arquivos JFS com journaling.

Mas, não marque para formatar a mesma, como mostram as imagens a seguir:

3.3. Veja como ficou o particionamento ao final das alterações:

4. Agora, apresento a segunda forma de deixar as partições do sistema com journal externo. Primeiro, certifique-se de que as partições que usarão journal externo estejam desmontadas.

Logue usando um LiveCD, ou usando outro sistema GNU/Linux que tenha instalado no mesmo disco, ou em disco diferente, e execute os seguintes comandos:

# jfs_mkfs -J journal_dev /dev/sdb1
# jfs_mkfs -J journal_dev /dev/sdb2

Estes comandos acima preparam os dispositivos “/dev/sdb1” e “/dev/sdb2” para armazenar o journal. E em seguida, use o comando jfs_tune para dizer ao sistema de arquivos JFS, que o log está anexado em uma partição diferente do sistema:

# jfs_tune -J device=/dev/sdb1 /dev/sda1
# jfs_tune -J device=/dev/sdb2 /dev/sda2

Agora, edite e acrescente algumas opções no “/etc/fstab” para deixar o JFS com melhor desempenho. Veja que o UUID usado, é da partição que foi formatada para ambos. Mude o campo do UUID de sua partição, pois com certeza é diferente do atual:

UUID=b8ff3909-37f7-431e-a634-873842017335 /     jfs   rw,errors=remount-ro,relatime

UUID=22a6a838-e8af-450d-887c-f2c40c6bbfa3 /home     jfs   rw,relatime

Porém, se quer ganhar mais desempenho ainda, sem importar-se com as atualizações de tempo de acesso nos diretórios e arquivos, coloque as seguintes opções no fstab:

UUID=b8ff3909-37f7-431e-a634-873842017335 /     jfs   rw,errors=remount-ro,noatime,nodiratime

UUID=22a6a838-e8af-450d-887c-f2c40c6bbfa3 /home     jfs   rw,noatime,nodiratime

* NOTA: É muito importante deixar esclarecido que se o dispositivo que contém o journal externo chegar ao fim de sua vida útil, os dados que estão contidos no sistema não poderão mais ser acessados, ou montados, para escrita (somente para leitura) mesmo usando usando Live CD ou de outro sistema presente na mesma máquina.

Mas não fique desesperado caso isso aconteça, pois poderá instalar um novo disco e criar uma nova partição que conterá o journal do F.S. do sistema, fazendo com que o sistema seja acessível novamente com journal na partição do novo disco.

Para isso, execute os seguintes comandos a partir de outro sistema na mesma máquina, ou de um LiveCD:

# jfs_mkfs -J journal_dev /dev/sdb1
# jfs_tune -J device=/dev/sdb1 /dev/sda1

No comando acima, estou supondo que o novo dispositivo que irá conter o journal é “/dev/sdb1”, e que o sistema está no “/dev/sda1”. Depois de executar os comandos, é só reiniciar a máquina e voltar a usar seu sistema.

Mas tenha em mente, que foi criado um novo journal e que o conteúdo do antigo foi perdido, de maneira que se o antigo log contém alguma informação para ser recuperada, a mesma foi perdida.

Tunando usando journal interno

Mesmo com journal interno, podemos deixar o JFS com melhor desempenho, e para isso, farei uso do mesmo esquema de particionamento usado anteriormente.

UUID=b8ff3909-37f7-431e-a634-873842017335 /     jfs   rw,errors=remount-ro,relatime

UUID=22a6a838-e8af-450d-887c-f2c40c6bbfa3 /home     jfs   rw,relatime

Agora, vamos adicionar algumas opções ao “/etc/fstab” para deixar o JFS com uma melhor performance ainda:

UUID=b8ff3909-37f7-431e-a634-873842017335 /     jfs   rw,errors=remount-ro,noatime,nodiratime

UUID=22a6a838-e8af-450d-887c-f2c40c6bbfa3 /home     jfs   rw,noatime,nodiratime

Observe que são as mesmas opções usadas com o journal externo. Mas mesmo o journal estando interno, as opções noatime e nodiratime já trazem um benefício no desempenho, pois os metadados não armazenarão informações referentes a acessos em arquivos e/ou diretórios. Senão, vai armazenar estas informações, e com certeza não irá gravar as mesmas no journal.

Lembre-se que não é o forte do JFS ter transferências de dados de alta velocidade, principalmente quando for de tamanho pequeno.

Tunando os sistemas de arquivos ext3 e ext4

Aplicarei a prática de tunar os sistemas de arquivos ext3 e ext4 na mesma página, pois o procedimento é igual para ambos os F.S. Usarei o journal externo e interno para ambos.

Mas não aplicarei as alterações antes da instalação do sistema operacional usado, e sim depois da instalação. Pois além de ser possível, é viável, já que muitos administradores de sistemas e usuários usam estes sistemas de arquivos como padrão em suas instalações.

Apresentando particionamento usado para aplicar as alterações:

  • Partição: /dev/sda1 com sistema de arquivos ext3 – Diretório root “/”;
  • Partição: /dev/sda2 com sistema de aquivos ext4 – Diretório home “/home”;
  • Partição: /dev/sda5 – Swap;
  • Partição: /dev/sdb1 – Partição usada para armazenar o journal externo da partição /dev/sda1;
  • Partição: /dev/sdb2 – Partição usada para armazenar o journal externo da partição /dev/sda2.

Caso tenha um particionamento diferente em sua máquina e/ou servidor, poderá fazer as operações do mesmo jeito. Porém, aconselho que antes de aplicar as alterações em uma máquina que está em produção, faça em uma máquina de testes, para poder avaliar quais alterações podem adequar- se às suas necessidades.

Tunando o ext3 e ext4 usando journal externo

Usando este esquema de particionamento apresentado e supondo que a instalação já foi feita com sucesso, vamos às alterações necessárias para usar journal externo. Tenha em mãos um LiveCD para executar os passos seguintes.

1. Certifique-se que o sistema de arquivos onde está instalado o sistema esteja desmontado. E em seguida, verifique o tamanho do bloco das partições do sistema usando os comandos descritos abaixo:

# tune2fs -l /dev/sda1 |grep -i “block size”
# tune2fs -l /dev/sda2 |grep -i “block size”

É necessário saber qual o tamanho do bloco do sistema de arquivos de cada partição que terá seu journal externo, porque cada partição que armazenará os logs precisará ter o mesmo tamanho de bloco.

2. Prepare as partições que receberão os journals:

# mke2fs -O journal_dev /dev/sdb1 -b 4096 -L journal-ext-sda1 105500
# mke2fs -O journal_dev /dev/sdb2 -b 4096 -L journal-ext-sda2 105500

As opções passadas ao comando mke2fs foram:

  • -O : Esta opção indica que irá ser adicionado e/ou removido do sistema de arquivos características específicas, ou seja, será habilitado alguns comportamentos com personalização. Diferentemente de quando usa-se os padrões na aplicação de uma sistema de arquivos.
  • journal_dev: Indica qual partição será preparada e usada para armazenar o journal de outra partição.
  • -b: Indica o tamanho do bloco do sistema de arquivos criado. Neste caso, o tamanho do bloco deve ser o mesmo da partição que contém o sistema, pois estas partições “/dev/sdb1” e “/dev/sdb2” irá armazenar os journals das partições “/dev/sda1” e “/dev/sda2”.
  • -L: Este parâmetro é opcional, pois o mesmo adiciona um rótulo, ou seja, um nome da partição para identificação.

E por fim, o número indicado no fim é o tamanho do journal em blocos. Para calcular corretamente o tamanho do journal armazenado, tenha em mente que 1024 blocos equivale a 1 Megabyte. No comando anterior especifiquei 105500, então o tamanho do log é 103 Megabytes.

3. Agora, faça o ext3 e ext4 não terem mais journal interno, para poderem usar os que foram criados anteriormente.

# tune2fs -O ^has_journal /dev/sda1
# tune2fs -O ^has_journal /dev/sda2

Verifique se as partições ainda têm journal:

# tune2fs -l /dev/sda1 | grep -i has_journal
# tune2fs -l /dev/sda2 | grep -i has_journal

Veja na imagem anterior, que os dispositivos não tem mais journal.

4. Anexe os journals das partições para “/dev/sda1” e “/dev/sda2” às partições que armazenaram o journal de ambas.

# tune2fs -j -J device=/dev/sdb1 /dev/sda1
# tune2fs -j -J device=/dev/sdb2 /dev/sda2

Execute os comando abaixo, e veja a nova localização dos journals para “/dev/sda1” e “/dev/sda2”:

# tune2fs -l /dev/sda1 | grep -i journal
# tune2fs -l /dev/sda2 | grep -i journal

Depois das alterações, veja como ficaram as partições que receberam os logs:

Tanto ext3 quanto ext4 usados nas partições do sistema, já estão rápidos com o logo externo, mas podemos deixar mais rápido ainda, fazendo uso do comando tune2fs ou do arquivo “/etc/fstab” para habilitar os modos de operação que os sistemas de arquivos ext3/4 possuem.

O padrão é ordered, assim como podemos habilitar outros comportamentos para os sistemas de arquivos usados.

Farei uso arquivo “/etc/fstab” para aplicar estes comportamentos.

No exemplo abaixo, estou indicando no ext3 (partição raiz) e ext4 (partição /home), que o modo de operação é writeback executando o comando tune2fs e adiciono a opção relatime fazendo com que tenha um ganho de desempenho muito bom para ambos os F.S.:

# tune2fs -o journal_data_writeback /dev/sda1
# tune2fs -o journal_data_writeback /dev/sda2

UUID=4ccfc585-1d20-4845-9c00-0d2a44bf8e0a /     ext3    errors=remount- ro,relatime    0    1

UUID=85eebfa7-88ae-4de8-8125-3cfbce5abe29 /home    ext4    errors=continue,rw,relatime    0   &nbs p;2

Veja que o comportamento passado anteriormente, principalmente passado pelo comando tune2fs alterando o modo de operação ‘data=writeback’, faz com ambos os F.S. fiquem mais vulneráveis à perda de dados caso ocorra algum erro no sistema, e o mesmo seja forçado a ser desligado de forma incorretamente. Mas, a perda de dados é mais para o arquivos abertos.

Por exemplo, você está editando um arquivo e no momento em que está fazendo a edição, falta energia, então, o conteúdo que não foi salvo, será perdido.

No exemplo abaixo, deixo ambos os F.S. com maior desempenho, mas deixando a desejar na consistência:

# tune2fs -o journal_data_writeback /dev/sda1
# tune2fs -o journal_data_writeback /dev/sda2

UUID=4ccfc585-1d20-4845-9c00-0d2a44bf8e0a /     ext3   errors=remount- ro,noatime,nodiratime,barrier=0,commit=40    0    1

UUID=85eebfa7-88ae-4de8-8125-3cfbce5abe29 /home     ext4   errors=continue,rw,noatime,nodiratime,barrier=0,commit=40     0    2

Observe que, além de estar usando o modo de operação writeback, estou passando para o sistema de arquivos que não serão gravadas atualizações de acesso a arquivo e nem a diretórios, assim, como também desabilito o barrier que dá mais desempenho.

Porém, deixa ext3 e ext4 com menos consistência, deixando seu sistema de arquivos mais vulnerável caso ocorra, por exemplo, quedas de energia.

Mas, uma característica ainda não abordada neste artigo e que acrescentei acima, é a commit.


Os sistemas de arquivos ext3/4 podem ser configurados para sincronizar os dados e metadados a cada “n” segundos para o journal. Sendo que o valor padrão é 5 segundos. Isto significa que, se usar o valor padrão que é 5, e sua máquina é desligada incorretamente, como por exemplo em uma queda de energia, você irá perder apenas os últimos 5 segundos de trabalho, isto é, se o seu sistema de arquivos não for danificado.

Mas graças ao journaling, este risco é diminuído. Se aumentamos o valor, o sistema de arquivos ficará mais rápido já que o intervalo de sincronização e acesso ao journaling irá aumentar e não será necessário fazer tantas sincronizações em pouco tempo.

Porém, se deseja deixar seu sistema de arquivos ext3/4 o mais consistente possível, perdendo muito desempenho, acrescente ao “/etc/fstab”, as seguintes opções:

# tune2fs -o journal_data /dev/sda1
# tune2fs -o journal_data /dev/sda2

UUID=4ccfc585-1d20-4845-9c00-0d2a44bf8e0a /     ext3   errors=remount- ro,barrier=1,sync    0    1

UUID=85eebfa7-88ae-4de8-8125-3cfbce5abe29 /home     ext4  errors=continue,rw,barrier=1,sync    0   &nbs p;2

Veja bem estas opções de montagem, pois seu sistema de arquivos ficará muito lento, mas em compensação, estará mais consistente.

Uma boa forma de colocar seu sistema de arquivos ext3/4 ao meio termo, bom desempenho com consistência, seria usar as seguintes opções de montagem:

# tune2fs -o journal_data_writeback /dev/sda2

UUID=4ccfc585-1d20-4845-9c00-0d2a44bf8e0a /     ext3  errors=remount- ro,barrier=1    0    1

UUID=85eebfa7-88ae-4de8-8125-3cfbce5abe29 /home     ext4  errors=continue,rw,barrier=1,commit=30    0  &nbs p; 2

Assim, mesmo com menos comportamentos habilitados e desabilitados, seu F.S. terá bom desempenho, pois ainda tem journal externo.

* Observação Importante: Caso a partição que contém o journal do sistema fique danificada e não possa mais ser acessada, ou o disco que contém o journal chegue ao fim de sua vida útil, seu sistema não poderá mais ser acessado, nem mesmo através de outros sistemas presentes no disco ou LiveCDs.

Para resolver isso, basta executar os seguintes comandos abaixo, para deixar seu sistema com journal e acessível mais uma vez. Mas antes, instale um novo disco que conterá a partição que irá armazenar o journal do sistema.

Supondo que o dispositivo que contém o sistema é “/dev/sda1”, e o novo dispositivo que irá armazenar o journal é “/dev/sdc1”. Lembre-se de criar uma tabela de partições para o novo disco e uma partição.

Primeiro, liste o tamanho do bloco do sistema de arquivos que contém o sistema:

# tune2fs -l /dev/sda1 |grep -i “block size”

Em seguida, prepare a partição que receberá o log do sistema de arquivos que contém o sistema, usando o tamanho do bloco que foi obtido pelo comando anterior. Abaixo, estou supondo que é 4096, se for diferente:

# mke2fs -O journal_dev /dev/sdc1 -b 4096 -L journal-ext-sda1 105500

Em seguida, retire o journal do sistema de arquivos que tem o sistema, e crie o novo journal usando os comandos:

# tune2fs -O ^has_journal /dev/sda1
# tune2fs -j -J device=/dev/sdc1 /dev/sda1

Veja que já usei estes comandos no inicio da página, mas não custa nada voltar a usá-los, principalmente quando é necessário recriar o journal.

Lembre-se que os logs armazenam informações para recuperar dados do seu sistema, então, se o seu sistema tiver alguma informação corrompida, ou que precisa recuperar, após a criação do novo journal a informação não poderá mais ser recuperada.

Tunando o ext3 e ext4 usando journal interno

Para tunar o ext3 e ou ext4 com journal interno é mais fácil. Podemos usar comandos assim como usados anteriormente e o arquivo “/etc/fstab” para isso. Usarei o mesmo esquema de particionamento usado com journal externo.

Primeiro, vamos mudar o modo de operação via comando, e fazer com que ambos os sistemas de arquivos trabalhem em modo writeback:

# tune2fs -o journal_data_writeback /dev/sda1
# tune2fs -o journal_data_writeback /dev/sda2

Como já alterei via comando o modo de operação, não será necessário alterar no “/etc/fstab”, mas mesmo assim acrescentarei algumas opções interessantes já explicadas.

UUID=4ccfc585-1d20-4845-9c00-0d2a44bf8e0a / ext3 errors=remount-ro,relatime 0 1

UUID=85eebfa7-88ae-4de8-8125-3cfbce5abe29 /home ext4 errors=continue,rw,relatime 0 2

Para o kernel tratar o sistema de arquivos ext3/4, que contém o diretório root (raiz) no modo de operação alterado, no caso para writeback, teremos que incluir uma opção ao GRUB.

Se tem mais de um sistema com ext3/4 no seu diretório raiz “/” e deseja mudar o modo de operação apenas para alguns, então edite o arquivo de configuração e coloque ao final da linha a opção:


Mas, se deseja incluir em todos os sistemas que usam ext3/4 no seu diretório raiz “/”, então edite o arquivo “/etc/default/grub”, usando seu editor favorito e deixe a linha abaixo:




E em seguida, execute como root o comando:

# update-grub

Depois disso, o seu kernel tratará o sistema de arquivos no modo writeback, caso precise alterar o modo de operação para outro journal (data), e/ou ordered, precisará fazer as mesmas alterações no mesmo arquivo, isto porque o sistema de arquivos já teve seu comportamento alterado com o comando tune2fs.

Porém, se deseja alterar o modo de operação em sistema de arquivos ext3/4 de qualquer partição que contém qualquer diretório, com exceção do raiz, não precisará fazer tais alterações nos arquivos editados anteriormente.

* Lembrando que isso só vale para F.S ext3/4 com journal interno.

Para deixar o F.S. ainda mais rápido, mas deixando a consistência do mesmo mais vulnerável, principalmente usando a opção barrier, deixe seu fstab como descrito abaixo. E se ainda não mudou o modo de operação para writeback, execute o comando abaixo e faça as alterações já explicadas:

# tune2fs -o journal_data_writeback /dev/sda1
# tune2fs -o journal_data_writeback /dev/sda2

UUID=4ccfc585-1d20-4845-9c00-0d2a44bf8e0a / ext3 errors=remount-ro,noatime,nodiratime,barrier=0,commit=40 0 1

UUID=85eebfa7-88ae-4de8-8125-3cfbce5abe29 /home ext4 errors=continue,rw,noatime,nodiratime,barrier=0,commit=40 0 2

* Não esqueça de alterar o arquivo “/etc/default/grub” e/ou alterar manualmente o arquivo de configuração do GRUB.

Mas, se deseja deixar o sistema de arquivos “/ext3/4” mais robusto perdendo desempenho, mude o “/etc/fstab” para o indicado abaixo, e altere o modo de operação usando o comando tune2fs.

No exemplo abaixo, deixo ambos os F.S. com mais desempenho, mas deixando a desejar na consistência:

# tune2fs -o journal_data /dev/sda1
# tune2fs -o journal_data /dev/sda2

UUID=4ccfc585-1d20-4845-9c00-0d2a44bf8e0a / ext3 errors=remount-ro,barrier=1,sync 0 1

UUID=85eebfa7-88ae-4de8-8125-3cfbce5abe29 /home ext4 errors=continue,rw,barrier=1,sync 0 2

Nesta última forma de uso explicada, teria que mudar o arquivo de configuração do GRUB, e colocar no final da linha que descreve a localização do kernel a seguinte linha:


Ou, editar o arquivo “/etc/default/grub” usando seu editor favorito e alterar a seguinte linha:




E depois, executar o comando:

# update-grub

Para deixar o sistema de arquivos ext3/4 em um meio termo, com um bom desempenho e consistência mesmo usando journal interno, seria usado as seguintes opções no “/etc/fstab”:

UUID=4ccfc585-1d20-4845-9c00-0d2a44bf8e0a / ext3 errors=remount-ro,barrier=1 0 1

UUID=85eebfa7-88ae-4de8-8125-3cfbce5abe29 /home ext4 errors=continue,rw,barrier=1,commit=40,relatime 0 2

Pois a partição que contém o diretório raiz iria manter o modo de operação padrão, assim como na partição /home, porém, /home teria uma ganho com as opções commit e relatime.

Benchmark básico depois de tunar os sistemas de arquivos para melhor desempenho

Depois de abordar como tunar cada sistema de arquivos citados no artigo, nada mais normal que testar o desempenho de cada um, para ver como cada um comporta-se diante dos testes.

E até porque, dada a curiosidade sobre como comportarão os sistemas de arquivos após as alterações no comportamento, não é mesmo? Mas, o melhor mesmo é usar no dia a dia, aí sim poderá ver realmente quais as vantagens ganhas.

Aqui, vou mostrar vários gráficos que comparam o desempenho de cada um, trata-se de benchmark básico.

Para esta série de testes de desempenho, usei uma máquina com:

  • Processador Intel® Core™2 Duo;
  • Placa mãe ASUS;
  • Memória RAM com capacidade 4 GB;
  • HD Samsumg SATA 3;
  • Sistema Debian 6.0.5;
  • kernel 3.2.0-0.bpo.2-amd64.

Todos os testes não informam o uso de CPU, apenas o tempo que foi necessário para concluir a tarefa, e foram feitos no prompt de comando.

As características usadas para cada sistema de arquivos que foram habilitadas para o benchmark:

– ReiserFS:

  • Journal externo;
  • As opções para alterar o comportamento ReiserFS foram adicionadas ao “/etc/fstab”:

– XFS:

  • Journal externo, criado com o seguinte comando:

    # mkfs.xfs -f -l logdev=/dev/sdb2,size=1g -d agcount=4 -i maxpct=5 /dev/sda8

  • As opções para alterar o comportamento para XFS foram adicionas ao “/etc/fstab”:

– JFS:

  • Journal externo;
  • As opções para alterar o comportamento para JFS foram adicionadas ao “/etc/fstab”:

– ext3:

  • Journal externo, o tamanho do journal criado é de 105500;
  • As opções para alterar o comportamento para ext3 foram adicionadas ao “/etc/fstab”:

    E alterei o modo de operação para writeback, usando o comando abaixo:

    # tune2fs -o journal_data_writeback /dev/sda8

– ext4:

  • Journal externo, o tamanho do journal criado é de 105500;
  • As opções para alterar o comportamento para ext3 foram adicionadas ao “/etc/fstab”:

    E alterei o modo de operação para writeback usando o comando abaixo:

    # tune2fs -o journal_data_writeback /dev/sda8

Primeiro teste

Trata-se de criar trinta mil arquivos de texto comum, sem nenhum conteúdo usando o comando touch. Para isso, desenvolvi um script para fazer todo o trabalho e todos o sistemas de arquivos concluíram o trabalho em poucos segundos.

Veja no gráfico abaixo o resultado:

Veja no gráfico, que ext4 e ext3 foram respectivamente os mais rápidos, seguido por ReiserFS, logo após JFS e por último XFS. Mas lembre-se que XFS não trabalha bem com arquivos pequenos, e sim com arquivos grandes.

Segundo teste

Trata-se de listar todos os trinta mil arquivos criados anteriormente. Todos os F.S. concluíram o trabalho em poucos segundos.

Veja no gráfico abaixo o resultado:

Veja que, mesmo todos usando o journal externo, o ReiserFS foi o mais rápido, seguido por JFS e XFS, ext3 e ext4 foram os mais lentos neste teste.

Terceiro teste

Trata-se da remoção de todos os trinta mil arquivos criados anteriormente, usando o comando rm. E mais uma vez, a conclusão da tarefa foi feita em poucos segundos.

Veja no gráfico abaixo o resultado:

Veja que, mais uma vez o XFS mostrou que não trabalha bem com arquivos pequenos e foi o último com um tempo bem acima dos outros sistemas de arquivos. Os mais rápidos foram ext3 seguido de ext4 e ReiserFS. O JFS não saiu-se bem no teste, pois o mesmo não trabalha bem com arquivos pequenos também.

Quarto teste

Trata-se da gravação de um arquivo de 1,3 Gigabytes de tamanho, e todos os sistemas de arquivos testados acabaram o trabalho em segundos.

Veja no gráfico abaixo o resultado:

Os sistemas ext4 e XFS foram, respectivamente, mais rápidos que os outro F.S. neste teste.

Quinto teste

Trata-se de empacotar e compactar usando o comando tar zcf o arquivo de 1,3 Gigabytes de tamanho, gravado anteriormente. Todos levaram quase um minuto para concluir o trabalho.

Veja no gráfico abaixo o resultado:

Neste teste, JFS e XFS foram os mais rápidos, respectivamente. ReiserFS foi o mais lento de todos.

Sexto teste

Trata-se de desempacotar e descompactar o arquivo compactado e empacotado anteriormente de 1,3 gigabytes. Mais uma vez, todos concluíram o trabalho em segundos.

Veja no gráfico abaixo o resultado:

XFS foi o mais rápido outra vez, comprovando que com arquivos grandes ele trabalha bem, ext4 foi o segundo mais rápido, seguido de ext3 e JFS. ReiserFS foi o que levou o maior tempo.

Sétimo teste

Trata-se do tempo levado para remover o arquivo de 1,3 Gigabytes gravado no teste anterior. O trabalho foi concluído em segundos.

Veja no gráfico abaixo o resultado:

O mais rápido neste foi JFS, terminando a remoção do arquivo em incrível um milésimo de segundo, seguidos de ReiserFS e ext4.

Oitavo teste

Trata-se de criar trinta mil diretórios usando o comando mkdir. Para isso, desenvolvi um script para este trabalho e o tempo de conclusão para todos os sistemas de arquivos foi em segundos.

Veja no gráfico abaixo o resultado:

ReiserFS foi o mais rápido na criação dessa avalanche de diretórios, seguido de XFS e JFS. Os ext3/4 ficaram para trás neste teste.

Nono teste

Trata-se de listar os trinta mil diretórios criados anteriormente. Todos acabaram o trabalho de listagem em segundos.

Veja no gráfico abaixo o resultado:

ReiserFS foi o mais rápido outra vez, seguido de JFS e XFS, que finalizaram o trabalho com o mesmo tempo. O ext4 foi o que levou mais tempo.

Décimo teste

Trata-se de remover todos os diretórios criados anteriormente. Todo o trabalho foi concluído em poucos segundos em todos o sistemas de arquivos testados.

Veja no gráfico abaixo o resultado:

Neste último teste, os mais rápidos foram ext3 e ext4, respectivamente. ReiserFS demostrou um ótimo desempenho também. XFS foi o que levou mais tempo para concluir o trabalho.

Nota-se neste benchmark básico, que alguns sistemas de arquivos, como XFS e ReiserFS, demostraram suas características. XFS com um desempenho muito bom para arquivos grandes e ReiserFS para arquivos pequenos.

Dá para perceber também, que alguns sistemas de arquivos tiveram melhor desempenho com journal externo do que outros.

Veja o ext3/4, teve em alguns testes, um desempenho abaixo do esperado, mas lembre-se de que a maioria dos testes foram feitos com trabalhos em massa, e que nem todas as características foram habilitadas em todos os sistemas de arquivos testados.

Considerações finais

O Sistema de arquivos com journal externo pode ganhar muito desempenho, mas lembre-se de que, se o dispositivo que armazena o journal não puder mais ser acessado, seja por qualquer motivo, o S.O. não poderá mais ser usado. Para acessá-lo novamente, é necessário criar um novo journal para o sistema de arquivos que contém o S.O.

No benchmark realizado e mostrado na página anterior, foram feitos vários testes, porém, para poder avaliar e validar a verdadeira vantagem de tunar um sistema de arquivos, nada melhor do que você mesmo testar e ver se as alterações vão atender às suas necessidades.

Veja também que algumas alterações abordadas no decorrer do artigo podem deixar o F.S. vulnerável, podendo deixar você na mão. Então, antes de aplicar tais alterações na máquina que está em produção, ou mesmo não aplicando-as, faça BACKUP.

Recomendações de uso

Para desktop que usa o diretório /home em partição separada da raiz e possui muitos arquivos pequenos. Use no diretório raiz o sistema de arquivos ReiserFS, e na /home, use ext4 ou próprio ReiserFS.

Caso tenha em um diretório vários arquivos grandes, use XFS com journal interno, como foi abordado no artigo. Pois o XFS tem um bom desempenho com arquivos grandes. Não use XFS com o journal externo, pois apesar de possível seu uso saiba do risco que corre, caso a partição que contém o journal ficar danificada, o seu sistema ficará inacessível.

E, para criar um novo journal externo para poder ter acesso outra vez aos seus dados, só aplicando outra vez o sistema de arquivos XFS na partição que contém o sistema.

Mas, se tem arquivos grandes em uma partição e deseja usar journal externo, use o sistema de arquivos JFS, pois o mesmo trabalha bem com arquivos grandes e tem um bom desempenho com log externo.

No caso de um servidor de rede que não armazena arquivos tão importantes, como DHCP e/ou proxy, deixe o diretório raiz com o sistema de arquivos ext4 ou ext3.