Eu estou entediado, então aqui estão mais alguns métodos sobre como concatenar um arquivo para si mesmo, principalmente com head
como uma muleta. Perdoe-me se eu me explicar demais, eu apenas gosto de dizer coisas: P
Assumindo que N
é o número de concatenações automáticas que você deseja fazer e que seu arquivo é denominado file
.
Variáveis:
linecount=$(<file wc -l)
total_repeats=$(echo "2^$N - 1" | bc) # obtained through the power of MATH
total_lines=$((linecount*(total_repeats+1)))
tmp=$(mktemp --suffix .concat.self)
Dada uma cópia de file
chamado file2
, total_repeats
é o número de vezes que file
precisaria ser adicionado a file2
para torná-lo o mesmo como se file
fosse concatenado a si mesmo N
vezes.
O MATH está aqui, mais ou menos: MATH (gist)
É o primeiro semestre da ciência da computação, mas já faz um tempo desde que eu fiz uma prova de indução, então eu não consigo superá-la ... (também esta classe de recursão é bem conhecida por ser 2^Loops
, então existe essa também ....)
POSIX
Eu uso algumas coisas que não são positivas, mas elas não são essenciais.
Para os meus propósitos:
yes() { while true; do echo "$1"; done; }
Ah, eu só usei isso. Oh bem, a seção já está aqui ...
Métodos
head
com rastreamento de linecount.
ln=$linecount
for i in $(seq 1 $N); do
<file head -n $ln >> file;
ln=$((ln*2))
done
Nenhum arquivo temporário, nenhum gato, nem mesmo muita matemática, toda alegria.
tee
com MATH
<file tee -a file | head -n $total_lines > $tmp
cat $tmp > file
Aqui tee
está lendo file
, mas permanentemente anexando a ele, então ele continuará lendo o arquivo até que head
pare. E sabemos quando pará-lo por causa de MATH . O acréscimo vai além, então usei um arquivo temporário. Você pode cortar as linhas em excesso de file
também.
eval
, o senhor das trevas!
eval "cat $(yes file | head -n $((total_repeats+1)) | tr '\n' ' ')" > $tmp
cat $tmp > file
Isso apenas se expande para cat file file file ...
e é avaliado.
Você pode fazer isso sem o arquivo $tmp
, também:
eval "cat $(yes file | head -n $total_repeats | tr '\n' ' ')" |
head -n $((total_lines-linecount)) >> file
O segundo head
"engana" cat
colocando um intermediário entre ele e a operação de gravação. Você pode enganar cat
com outro cat
, mas isso tem um comportamento inconsistente. Tente isto:
test_double_cat() {
local Expected=0
local Got=0
local R=0
local file="$(mktemp --suffix .double.cat)"
for i in $(seq 1 100); do
printf "" > $file
echo "1" >> $file
echo "2" >> $file
echo "3" >> $file
Expected=$((3*$(<file wc -l)))
cat $file $file | cat >> $file
Got=$(<file wc -l)
[ "$Expected" = "$Got" ] && R="$((R+1))"
done
echo "Got it right $R/100"
rm $file
}
sed
:
<file tr '\n' 'find_missing_char() {
local file="${1:-/dev/stdin}"
firstbyte="$(<$file fold -w1 | od -An -tuC | sort -un | head -n 1)"
if [ ! "$firstbyte" = "0" ]; then
echo "linecount=$(<file wc -l)
total_repeats=$(echo "2^$N - 1" | bc) # obtained through the power of MATH
total_lines=$((linecount*(total_repeats+1)))
tmp=$(mktemp --suffix .concat.self)
"
else
printf "\$(printf '%03o\t' $((firstbyte-1)) )"
fi
}
' |
sed -e "s/.*/$(yes ' yes() { while true; do echo "$1"; done; }
' | head -n $total_repeats | tr -d '\n')/g" |
tr 'ln=$linecount
for i in $(seq 1 $N); do
<file head -n $ln >> file;
ln=$((ln*2))
done
' '\n' >> file
Força sed
a ler o arquivo inteiro como uma linha, captura todo o arquivo e cola $total_repeats
do número de vezes.
Isso falhará, é claro, se você tiver algum caractere nulo em seu arquivo. Escolha um que você sabe que não está lá.
<file tee -a file | head -n $total_lines > $tmp
cat $tmp > file
Isso é tudo por agora rapazes, espero que essa resposta arbitrária não tenha incomodado ninguém. Eu testei todos eles muitas vezes, mas eu sou apenas um usuário de shell de dois anos, então tenha isso em mente, eu acho. Agora para dormir ...
rm $tmp