Je m'ennuie donc voici quelques méthodes supplémentaires pour concaténer un fichier à lui-même, principalement avec head
une béquille. Pardonnez-moi si je me surexplique, j'aime juste dire des choses: P
En supposant que N
le nombre d'auto-concaténations que vous voulez faire et que votre fichier est nommé file
.
Variables:
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)
Étant donné une copie de file
appelé file2
, total_repeats
c'est le nombre de fois file
qu'il faudrait ajouter pour file2
le rendre comme s'il file
était concaténé à lui-même N
fois.
Dit MATH est ici, plus ou moins: MATH (gist)
C'est des trucs informatiques du premier semestre mais ça fait un moment que je n'ai pas fait de preuve d'induction donc je ne peux pas m'en remettre 2^Loops
...
POSIX
J'utilise quelques éléments non posix mais ils ne sont pas essentiels. Pour mes fins:
yes() { while true; do echo "$1"; done; }
Oh, je l'ai seulement utilisé. Eh bien, la section est déjà là ...
Les méthodes
head
avec suivi linecount.
ln=$linecount
for i in $(seq 1 $N); do
<file head -n $ln >> file;
ln=$((ln*2))
done
Pas de fichier temporaire, pas de chat, pas encore trop de maths, toute joie.
tee
avec MATH
<file tee -a file | head -n $total_lines > $tmp
cat $tmp > file
Voici la tee
lecture file
mais en y ajoutant perpétuellement, donc il continuera à lire le fichier en boucle jusqu'à ce head
qu'il s'arrête. Et nous savons quand l'arrêter à cause de MATH . L'ajout passe par dessus bord, j'ai donc utilisé un fichier temporaire. Vous pouvez également couper les lignes en excès file
.
eval
, le seigneur des ténèbres!
eval "cat $(yes file | head -n $((total_repeats+1)) | tr '\n' ' ')" > $tmp
cat $tmp > file
Cela se développe cat file file file ...
et l'évale. Vous pouvez aussi le faire sans le $tmp
fichier:
eval "cat $(yes file | head -n $total_repeats | tr '\n' ' ')" |
head -n $((total_lines-linecount)) >> file
La seconde head
"astuces" cat
en mettant un intermédiaire entre elle et l'opération d'écriture. Vous pouvez également tromper cat
avec un autre cat
, mais cela a un comportement incohérent. Essaye ça:
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' '\0' |
sed -e "s/.*/$(yes '\0' | head -n $total_repeats | tr -d '\n')/g" |
tr '\0' '\n' >> file
Force la sed
lecture de l'ensemble du fichier sous forme de ligne, capture l'intégralité de celui-ci, puis le colle $total_repeats
plusieurs fois.
Cela échouera bien sûr si vous avez des caractères nuls dans votre fichier. Choisissez celui dont vous savez qu'il n'est pas là.
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 "\0"
else
printf "\\$(printf '%03o\t' $((firstbyte-1)) )"
fi
}
C'est tout pour l'instant les gars, j'espère que cette réponse arbitraire n'a dérangé personne. Je les ai tous testés plusieurs fois, mais je ne suis qu'un utilisateur shell de deux ans, alors gardez cela à l'esprit, je suppose. Maintenant pour dormir ...
rm $tmp