Como crio diretórios nomeados após cada mês?

8

Eu gostaria de criar um nome de diretório para cada mês. Eu sei, depois de algumas brincadeiras com o shell, que:

date -d 1/01 +%b # Gives Jan
date -d 2/01 +%b # Gives Feb
.
date -d 12/01 +%b # Gives Dec

Então, eu usei a expansão de chaves echo {1..12}/01e tentei xargs:

echo {1..12}/01 | xargs -n 1 -I {} date -d {} +%b

Mas falha miseravelmente: / (depois eu gostaria de me inscrever mkdir). Como posso fazer isso?

JammingThebBits
fonte
4
Você parece estar programando demais isso. Se houver uma razão, ajudaria se você explicasse por que simplesmente não escreve 12 linhas, "mkdir" Jan "; mkdir" Feb "; ...". Se você precisar fazer isso várias vezes, coloque o código em uma função e chame conforme necessário.
Jamesqf
4
Por que você está nomeando seus diretórios com os nomes dos meses em vez dos números 01-12? Tem que ser estranho tê-los lsed em ordem alfabética (abril, agosto, dezembro, fevereiro, janeiro, julho, junho, março, maio, novembro, outubro e setembro).
user1024
2
@jamesqf Por que você faria isso quando pode simplesmente fazer mkdir january february [...]? A menos que você realmente precise criá-los separadamente, não há necessidade de fazê-lo da maneira sugerida.
Pryftan
@ user1024 Normalmente, eu concordo com você, mas tenho para um caso de uso o nome dos meses (embora em minúsculas); em outro eu tenho 01janeiro etc. Quem pode dizer? Existem inúmeras razões pelas quais pode ou pode ser melhor de uma maneira ou de outra. (Mas sim - se a triagem é um problema ...) #
1070
@Pryftan: Apenas uma preferência pessoal para linhas mais curtas :-) Além disso, se eu quiser mudar mais tarde para "01Jan", é mais fácil no meu editor fazer um "c / / 01/12 1" do que fazer a alteração em uma linha.
Jamesqf

Respostas:

17

Com -I, xargsobtém um argumento por linha em oposição ao padrão de um argumento por palavra (em branco ou em nova linha, possivelmente entre aspas) palavra sem -I(e implica -n). Portanto, no seu exemplo, dateé chamado apenas uma vez com {}expandido para toda a saída de echo(que está em uma linha), menos a nova linha à direita.

Aqui você pode fazer (observe que essa -dé uma extensão GNU):

printf '%s\n' {1..12}/01 | xargs -I {} date -d {} +%b | xargs mkdir --

(observe que ele não funcionará corretamente em locais onde as abreviações do nome do mês contenham espaços ou caracteres de aspas; com o GNU xargs, você pode contornar isso usando xargs -d '\n' mkdir --)

Agora, para obter a lista de abreviações do mês em seu código do idioma, consultar o código do idioma diretamente faria mais sentido:

(IFS=';'; set -o noglob; mkdir -- $(locale abmon))

(veja também locale -k LC_TIMEpara ver todos os dados de localidade na LC_TIMEcategoria).

Ou nativamente em zsh:

zmodload zsh/langinfo
mkdir -- ${(v)langinfo[(I)ABMON_*]}

Pelo menos nos sistemas GNU, em alguns locais, as abreviações do mês são preenchidas com largura fixa com espaços:

$ LC_ALL=et_EE.UTF-8 locale title abmon
Estonian locale for Estonia
jaan ;veebr;märts;apr  ;mai  ;juuni;juuli;aug  ;sept ;okt  ;nov  ;dets
$ LC_ALL=zh_TW.UTF-8 locale title abmon
Chinese locale for Taiwan R.O.C.
 1月; 2月; 3月; 4月; 5月; 6月; 7月; 8月; 9月;10月;11月;12

Você pode remover esse preenchimento.

Os espaços à frente seriam removidos por xargs -I, mas não os à direita. Com zsh:

zmodload zsh/langinfo
set -o extendedglob
mkdir -- ${${${(v)langinfo[(I)ABMON*]}##[[:space:]]#}%%[[:space:]]#}
Stéphane Chazelas
fonte
Agradável! Não sabia sobre locale abmon.
maulinglawns
Resposta agradável, mas tl; dr: IFS=';'; set -o noglob; mkdir -- $(locale abmon). ;)
Skippy le Grand Gourou
9

Tente um loop?

$ for m in {1..12}; do
> date -d "$m"/01 +%b
> done
jan
feb
mar
apr
maj
jun
jul
aug
sep
okt
nov
dec

Se você deseja criar um diretório para cada mês, eu faria algo como:

for m in {1..12}; do newdir=$(date -d "$m"/01 +%b); mkdir "$newdir"; done
maulinglawns
fonte
Note que {1..12}é um basismo. Para um shell POSIX, o uso for m in $(seq 1 12)...(embora note que seqem si não é obrigatória por POSIX)
Radovan Garabik
2
@ RadovanGarabík, tecnicamente, {1..12}é um zshism, copiado posteriormente por ksh93, bash e várias outras conchas.
Stéphane Chazelas
5

Nos shells com expansão de chave e na data de aceitação da entrada DATAFILE, tente

echo {01..12}/01$'\n' | date -f- +"mkdir %b"

e encha a concha se estiver satisfeito com o resultado.

RudiC
fonte
5

Seu comando não funciona, devido ao uso de -Ialterações no delimitador de xargs:

-I replace-str
Substitua ocorrências de replace-str nos argumentos iniciais pelos nomes lidos na entrada padrão. Além disso, espaços em branco não citados não finalizam itens de entrada; em vez disso, o separador é o caractere de nova linha.

Você pode adicionar -d " "ao xargs para fazê-lo funcionar. Mas você nem precisa -I{}no seu caso:

Tente isso,

echo {1..12}/01 | xargs -n1 date +%b -d | xargs mkdir
pLumo
fonte
11
Note que para o GNU dateaceitar opções após argumentos não opcionais como esse, não deve haver uma POSIXLY_CORRECTvariável no ambiente.
Stéphane Chazelas
3

Você está tão perto.

O problema é que o eco está produzindo uma única linha 1/01 2/01 3/01 4/01 5/01 6/01 7/01 8/01 9/01 10/01 11/01 12/01e o xargs está usando o caractere de nova linha como separador de campos (não o espaço).

A solução: diga eco para colocar um espaço entre cada campo.

echo -e {1..12}/01\\n | xargs -n 1 -I {} date -d {} +%b

Eu apenas inseri \\nno final do eco.

Então, para fazer os diretórios adicionarem |xargs mkdir

por exemplo

echo -e {1..12}/01\\n | xargs -n 1 -I {} date -d {} +%b | xargs mkdir

ctrl-alt-delor
fonte
1

A maneira mais simples e robusta de fazer isso:

mkdir jan feb mar apr maj jun jul aug sep okt nov dec

Afinal, é uma lista estática de meses ...

Se você pretende usar o GNU date(assumindo um $IFSGNU não modificado e datesemelhante ao seu date -d):

mkdir $( printf '%s\n' {1..12}/01 | date -f - +%b )
Kusalananda
fonte
2
Exceto que ele não cria abreviações para o nome do mês no idioma do usuário.
Stéphane Chazelas
@ StéphaneChazelas A menos que sejam suecos, como eu :-)
Kusalananda