Count number of files and print the last file - bash

I am missing some episodes of the TV series friends, and I would like to know how many files I am missing per season. I would like to print out the last episode of each season and the number of files for each season.
The files have the format:
Friends S01E01 The Pilot.mkv
Friends S10E11 The One Where the Stripper Cries.mkv

The following bash script/oneliner should give you what you need, with details because it might help if you have the last episode of a season but earlier episodes are missing:
#!/bin/bash
ls Friends* | cut -c10-14 | \
awk -F'E' '{arr[$1]=arr[$1]" "$2; num[$1]++;} END { for (i in arr) printf "Season %s (%2d files) : %s\n", i, num[i], arr[i] }' | \
sort
Using awk, arrays with index being the number of the season are incremented to count the number of episodes, and also print the list of episode numbers so you can easily see which ones are missing. I used cut with columns 10 to 14 because in this case, we can safely assume that the numbers are where we want them.
The output is as follows:
Season 01 ( 9 files) : 01 02 03 04 05 06 07 08 09
Season 02 (10 files) : 01 02 03 04 05 06 07 08 09 10
Season 03 (10 files) : 01 02 03 04 05 06 07 08 09 10
Season 04 (10 files) : 01 02 03 04 05 06 07 08 09 10
Season 05 ( 9 files) : 01 03 04 05 06 07 08 09 10
Season 06 (10 files) : 01 02 03 04 05 06 07 08 09 10
Season 07 (10 files) : 01 02 03 04 05 06 07 08 09 10
Season 08 (10 files) : 01 02 03 04 05 06 07 08 09 10
Season 09 (10 files) : 01 02 03 04 05 06 07 08 09 10
Season 10 ( 7 files) : 01 02 03 04 05 06 10

The following bash scipt will work:
#!/bin/bash
for i in {01..10}
do
ls Friends\ S$i* | tail -n 1
ls Friends\ S$i* | wc -l
printf "\n"
done
It will produce results as follows:
Friends S01E24 The One Where Rachel Finds Out.mkv
24
Friends S02E24 The One with Barry and Mindy's Wedding.mkv
24

Related

Sed command to find string and replace another string (txt format)

I'm triying to find a string in a txt format and each time it's found then look for an specific string to change for another string.
Imagine the next hexa txt:
02 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 09 01 27 30 22 a0 0a 80 08 33 04 03 92 22 14
00 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 09 01 27 30 22 a0 0a 80 08 33 04 03 92 22 14
I need that each time I encounter a 2a sequence to look for 09 01 sequence and replace with 03 02.
Expected output:
02 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 03 02 27 30 22 a0 0a 80 08 33 04 03 92 22 14
00 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 03 02 27 30 22 a0 0a 80 08 33 04 03 92 22 14
Im triying something this:
sed -i 's/09 01\(.*2a\)/03 02/g' packet.txt
I would do this with awk:
$ awk ' { for ( i = 1; i <= NF; ++i ) {
if ( $i == "2a" )
r = 1
if ( r && $i == "09" && $(i+1) == "01" ) {
r = 0
$i = "03"
$++i = "02"
}
}
}
1 ' hexa.txt > hexa.txt.modified
Grep the differences:
$ sdiff hexa.txt hexa.txt.modified
02 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1 02 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01 09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 09 01 27 30 22 a0 0a 80 08 33 04 03 92 22 14 | b7 03 02 27 30 22 a0 0a 80 08 33 04 03 92 22 14
00 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1 00 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01 09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 09 01 27 30 22 a0 0a 80 08 33 04 03 92 22 14 | b7 03 02 27 30 22 a0 0a 80 08 33 04 03 92 22 14
Assuming you mean: "only replace if it occurs after 2a", then you can do it by transforming the bytes, so that only one 2a occurs on each line, e.g.:
<hexa.txt tr '\n' ' ' | sed 's/2a/\n&/g'
Now all you need to do is only replace 09 01 when the line starts with 2a, e.g.:
sed -E 's/(^2a.*) 09 01/\1 03 02/'
Now go back to the original formatting, i.e. 16 bytes per line:
tr '\n' ' ' | xargs -n16
All together:
<hexa.txt tr '\n' ' ' | sed 's/2a/\n&/g' |
sed -E 's/(^2a.*) 09 01/\1 03 02/' |
tr '\n' ' ' | xargs -n16
Output:
02 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 03 02 27 30 22 a0 0a 80 08 33 04 03 92 22 14
00 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 03 02 27 30 22 a0 0a 80 08 33 04 03 92 22 14
If this can help,
cat *.txt | sed '/2a/s/09 01/02 03/g'
Alternative awk solution using GNU awk:
awk 'BEGIN { RS="2a" } { ORS=RS } $0 ~ /09 01/ { $0=gensub("09 01","03 02","g",$0)}1' file
Set 2a as the record separator. Check each record for "09 01". If it exists, replace "09 01" with "03 02" with the gensub function and set this as $0. Use short hand 1 to print the record after setting the output record separator the same as the record separator.
This might work for you (GNU sed):
sed -zE 's/^/\x00/ # introduce a unique delimiter
:a;/\x00$/{s///;b} # remove delimiter at end-of-file
/\x002a/!{s/\x00(.)/\1\x00/;ba} # if not 2a pass over next char
s//2a\x00/ # next char is 2a prep for next string
:b;/\x00$/ba # is it end of file
/\x0009(\s)01/{s//03\102\x00/;ba} # replace string and prep for 2a again
s/\x00(.)/\1\x00/;bb' file # not desired string so pass over char
Since the desired string (in this case09 01) may occur on another line or within in the same line twice or more, line processing is not feasible. Processing must be at character level and in this solution the entire file is processed as one string (see -z option).
Two cases are identified:
The key (in this case 2a), processing within the place holder :a.
The string to be replaced (09 01 with 03 02), processing within the place holder :b.
Once the key is identified, processing passes to the next case. Once the desired string has been replaced, processing is passed back the first case. Either case can terminate processing when the end-of-file is encountered.
N.B. The solution relies on the file not containing the null character hex 00.

How to use uniq-c on sorted file

I have got sorted file that looks like this:
2019 02 09 07 00
2019 02 09 07 00
2019 02 09 08 00
2019 02 09 08 00
2019 02 09 08 00
2019 02 09 08 00
2019 02 09 08 00
However, when I run uniq -c over that file, it doesn't count occurrences as one would expect:
1 2019 02 09 07 00
1 2019 02 09 07 00
1 2019 02 09 08 00
1 2019 02 09 08 00
1 2019 02 09 08 00
1 2019 02 09 08 00
1 2019 02 09 08 00
The desired output should look like this:
2 2019 02 09 07 00
5 2019 02 09 08 00
I am looking for portable, POSIX compliant solution in shell. Thanks!
Alright, I have found the solution. I was processing the file by line and indeed uniq was working with only the line and not the file as a whole.

Prepend hex string to the content of binary file

I have these 2 arrays representing hexadecimal numbers and I want to write to a file in binary format.
I convert to hexadecimal string like this:
a=["A2","48","04","03","EE","72","B4","6B"]
b=["1A","28","18","06","07","00","11","86","05","01","01","01","A0"]
hex_string1 = a.map{|b| b.to_i(16)}.pack("C*")
hex_string2 = b.map{|b| b.to_i(16)}.pack("C*")
Now I want to write to a file the hex_string2 first and then prepend (with offset "0") the hex_string1 to the file.
I'm proceeding like this but the output is incorrect.
File.binwrite("outfile.bin",hex_string2)
File.binwrite("outfile.bin",hex_string1,0)
The current output is:
A2 48 04 03 EE 72 B4 6B 05 01 01 01 A0
And the correct content within the "output.bin" would be like this:
A2 48 04 03 EE 72 B4 6B 1A 28 18 06 07 00 11 86 05 01 01 01 A0
How would be the way to do this?
You should write second string with the offset by the size of first string:
File.binwrite("outfile.bin",hex_string2,hex_string1.size)
File.binwrite("outfile.bin",hex_string1,0)
In this case you'll get exactly what you want:
A2 48 04 03 EE 72 B4 6B 1A 28 18 06 07 00 11 86 05 01 01 01 A0

Range with leading zero in bash

How to add leading zero to bash range?
For example, I need cycle 01,02,03,..,29,30
How can I implement this using bash?
In recent versions of bash you can do:
echo {01..30}
Output:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Or if it should be comma separated:
echo {01..30} | tr ' ' ','
Which can also be accomplished with parameter expansion:
a=$(echo {01..30})
echo ${a// /,}
Output:
01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
another seq trick will work:
seq -w 30
if you check the man page, you will see the -w option is exactly for your requirement:
-w, --equal-width
equalize width by padding with leading zeroes
You can use seq's format option:
seq -f "%02g" 30
A "pure bash" way would be something like this:
echo {0..2}{0..9}
This will give you the following:
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Removing the first 00 and adding the last 30 is not too hard!
This works:
printf " %02d" $(seq 1 30)

Limit keywords for day in a Google Analytics API request

I'd like to know if there's a way to get the top 5 keywords by grouping them by days of the current month.
I'd like to receive a dataset like the following as result.
Supposing today is 4 of December i want to retrieve data for days from 1 to 4 of December, limiting the number of keywords for day to 5:
Day Keyword Visits
----------------------
01 keyword1 703
01 keyword2 688
01 keyword3 115
02 keyword1 109
02 keyword2 66
02 keyword3 53
02 keyword4 40
02 keyword5 23
03 keyword1 23
03 keyword2 19
03 keyword3 17
04 keyword1 14
04 keyword2 14
What i've currently done is setting the following parameters:
(you can test it here if you have a ganalytics account: http://code.google.com/intl/it-IT/apis/analytics/docs/gdata/gdataExplorer.html)
Dimensions: ga:day,ga:keyword
Metrics: ga:visits
Filters: ga:medium==organic;ga:keyword!=(not provided)
Sort: ga:day,-ga:visits,ga:keyword
Now i just need a method to limit the number of keywords for day (if possible).

Resources