Read two files simultsneously value by value using regexp - regex

Doing small helping tool for combining two text files into one.
These files stores a big 2D arrays of float values. Here is some of them:
File 1
-0,1296169 -0,1286087 -0,1276232 ...
-0,1288124 -0,1278683 -0,1269373 ...
-0,1280221 -0,1271375 -0,12626 ...
...
File 2
-0,1181779 -0,1200798 -0,1219472 ...
-0,1198357 -0,1216468 -0,1234369 ...
-0,1214746 -0,1232006 -0,1249159 ...
...
both may have hunderds of rows and columns ...
Values also can be in scientific form (etc. 1.234e-003).
My goal is to read two files simultaneously value by value and write output, while fixing delimeter from comma to point and conver from scientific form to standard in the process.
This version of program combines only prepeared files (delimeter changed to point, values represented in standard form and values moved "one value per line"), but making these preparation is unreal if file have more than million of values.
Here is what i have for now:
import (
"bufio"
"fmt"
"io"
"os"
"regexp"
)
func main() {
file_dB, err := os.Open("d:/dB.txt")
if err != nil {
fmt.Printf("error opening file: %v\n", err)
os.Exit(1)
}
file_dL, err := os.Open("d:/dL.txt")
if err != nil {
fmt.Printf("error opening file: %v\n", err)
os.Exit(1)
}
file_out, err := os.Create("d:/out.txt") // also rewrite existing !
if err != nil {
fmt.Printf("error opening file: %v\n", err)
os.Exit(1)
}
dB := bufio.NewReader(file_dB)
dL := bufio.NewReader(file_dL)
err = nil
i := 1
for {
line1, _, err := dB.ReadLine()
if len(line1) > 0 && line1[len(line1)-1] == '\n' {
line1 = line1[:len(line1)-1]
}
line2, _, err := dL.ReadLine()
if len(line2) > 0 && line2[len(line2)-1] == '\n' {
line2 = line2[:len(line2)-1]
}
if len(line1) == 0 || len(line2) == 0 || err == io.EOF {
fmt.Println("Total lines done: ", i)
break
} else if err != nil {
fmt.Printf("Error while reading files: %v\n", err)
os.Exit(1)
}
i++
str := string(line1) + ";" + string(line2) + "\n"
if _, err := file_out.WriteString(str); err != nil {
panic(err)
}
}
}
How can i use regexp to make this program read unprepeared files (first listing) value by value and form it like:
-0.129617;-0.118178
-0.128609;-0.120080
-0.127623;-0.121947
...
Input files always formed in same way:
-decimal separator is comma
-one space after value (even if it last in a row)
-newline in the end of line
Previously used expression like ([-?])([0-9]{1})([,]{1})([0-9]{1,12})( {1}) and Notepad++ replace function to split line-of-values into one-value-per-line (combined to new vaules used expression like $1$2.$4\r\n\), but its mess if 'scientific form' value happens.
So is there any way to read files value by value without messing with splitting line into slices/substrings and working over them?

Thanks for help, with points of view of another peoples i've found my own solution.
What this tool does? Generally it combines two text files to one.
Where i've used it? Creating "Generic ASCII" text file for "Country specific coordinate system tool". Input text files are ASCII export of GRID files from GIS applications (values in arc degrees expected). Later this file may be used to fix local coordinate shifts when working with precise GPS/GNSS receivers.
Here what i've "developed":
package main
import (
"bufio"
"fmt"
"os"
"regexp"
"strconv"
"strings"
)
func main() {
file_dB, err := os.Open("d:/dB.txt")
if err != nil {
fmt.Printf("error opening file: %v\n", err)
os.Exit(1)
}
defer file_dB.Close()
file_dL, err := os.Open("d:/dL.txt")
if err != nil {
fmt.Printf("error opening file: %v\n", err)
os.Exit(1)
}
defer file_dL.Close()
file_out, err := os.Create("d:/out.txt") // also rewrite existing !
if err != nil {
fmt.Printf("error opening file: %v\n", err)
os.Exit(1)
}
defer file_out.Close()
dB := bufio.NewReader(file_dB)
dL := bufio.NewReader(file_dL)
err = nil
xcorn_float := 0.0
ycorn_float := 0.0
cellsize_float := 0.0
ncols := regexp.MustCompile("[0-9]+")
nrows := regexp.MustCompile("[0-9]+")
xcorn := regexp.MustCompile("[0-9]*,[0-9]*")
ycorn := regexp.MustCompile("[0-9]*,[0-9]*")
cellsize := regexp.MustCompile("[0-9]*,[0-9]*")
nodataval := regexp.MustCompile("-?d+")
tmp := 0.0
// n cols --------------------
ncols_dB, err := dB.ReadString('\n')
if err != nil {
panic(err)
}
ncols_dL, err := dL.ReadString('\n')
if err != nil {
panic(err)
}
if ncols.FindString(ncols_dB) != ncols.FindString(ncols_dL) {
panic(err)
}
ncols_dB = ncols.FindString(ncols_dB)
// n rows --------------------
nrows_dB, err := dB.ReadString('\n')
if err != nil {
panic(err)
}
nrows_dL, err := dL.ReadString('\n')
if err != nil {
panic(err)
}
if nrows.FindString(nrows_dB) != nrows.FindString(nrows_dL) {
panic(err)
}
nrows_dB = nrows.FindString(nrows_dB)
// X --------------------
xcorn_dB, err := dB.ReadString('\n')
if err != nil {
panic(err)
}
xcorn_dL, err := dL.ReadString('\n')
if err != nil {
panic(err)
}
if xcorn.FindString(xcorn_dB) != xcorn.FindString(xcorn_dL) {
panic(err)
}
xcorn_float, err = strconv.ParseFloat(strings.Replace(cellsize.FindString(xcorn_dB), ",", ".", 1), 8)
xcorn_float *= 3600.0
// Y --------------------
ycorn_dB, err := dB.ReadString('\n')
if err != nil {
panic(err)
}
ycorn_dL, err := dL.ReadString('\n')
if err != nil {
panic(err)
}
if ycorn.FindString(ycorn_dB) != ycorn.FindString(ycorn_dL) {
panic(err)
}
ycorn_float, err = strconv.ParseFloat(strings.Replace(cellsize.FindString(ycorn_dB), ",", ".", 1), 8)
ycorn_float *= 3600.0
// cell size --------------------
cellsize_dB, err := dB.ReadString('\n')
if err != nil {
panic(err)
}
cellsize_dL, err := dL.ReadString('\n')
if err != nil {
panic(err)
}
if cellsize.FindString(cellsize_dB) != cellsize.FindString(cellsize_dL) {
panic(err)
}
cellsize_float, err = strconv.ParseFloat(strings.Replace(cellsize.FindString(cellsize_dB), ",", ".", 1), 8)
cellsize_float *= 3600.0
// nodata value --------------------
nodataval_dB, err := dB.ReadString('\n')
if err != nil {
panic(err)
}
nodataval_dL, err := dL.ReadString('\n')
if err != nil {
panic(err)
}
if nodataval.FindString(nodataval_dB) != nodataval.FindString(nodataval_dL) {
panic(err)
}
nodataval_dB = nodataval.FindString(nodataval_dB)
fmt.Print(nodataval_dB)
//making header
if _, err := file_out.WriteString("name\n3;0;2\n1;2;" + nrows_dB + ";" + ncols_dB + "\n" + strconv.FormatFloat(xcorn_float, 'f', -1, 32) + ";" + strconv.FormatFloat(ycorn_float, 'f', -1, 32) + ";" + strconv.FormatFloat(cellsize_float, 'f', -1, 32) + ";" + strconv.FormatFloat(cellsize_float, 'f', -1, 32) + "\n1\n"); err != nil {
panic(err)
}
// valuses --------------------
for {
line1, err := dB.ReadString(' ')
if err != nil {
break
}
if tmp, err = strconv.ParseFloat(strings.TrimSpace(strings.Replace(line1, ",", ".", 1)), 64); err == nil {
line1 = strconv.FormatFloat(tmp, 'f', 8, 64)
}
line2, err := dL.ReadString(' ')
if err != nil {
break
}
if tmp, err = strconv.ParseFloat(strings.TrimSpace(strings.Replace(line2, ",", ".", 1)), 64); err == nil {
line2 = strconv.FormatFloat(tmp, 'f', 8, 64)
}
if err != nil {
panic(err)
}
str := string(line1) + ";" + string(line2) + "\n"
if _, err := file_out.WriteString(str); err != nil {
panic(err)
}
}
}
If you have any recomendations - feel free to leave a comment!

For example,
package main
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"strconv"
"strings"
)
var comma, period = []byte{','}, []byte{'.'}
func readNext(r io.Reader) func() (float64, error) {
s := bufio.NewScanner(r)
var fields []string
return func() (float64, error) {
if len(fields) == 0 {
err := io.EOF
for s.Scan() {
line := bytes.Replace(s.Bytes(), comma, period, -1)
fields = strings.Fields(string(line))
if len(fields) > 0 {
err = nil
break
}
}
if err := s.Err(); err != nil {
return 0, err
}
if err == io.EOF {
return 0, err
}
}
n, err := strconv.ParseFloat(fields[0], 64)
fields = fields[1:]
if err != nil {
return 0, err
}
return n, nil
}
}
func main() {
in1Name := `in1.data`
in2Name := `in2.data`
outName := `out.data`
in1, err := os.Open(in1Name)
if err != nil {
fmt.Fprint(os.Stderr, err)
return
}
defer in1.Close()
in2, err := os.Open(in2Name)
if err != nil {
fmt.Fprint(os.Stderr, err)
return
}
defer in2.Close()
out, err := os.Create(outName)
if err != nil {
fmt.Fprint(os.Stderr, err)
return
}
defer out.Close()
outw := bufio.NewWriter(out)
defer outw.Flush()
next1 := readNext(in1)
next2 := readNext(in2)
for {
n1, err1 := next1()
n2, err2 := next2()
if err1 == io.EOF && err2 == io.EOF {
break
}
if err1 != nil || err2 != nil {
fmt.Fprint(os.Stderr, err1, err2)
return
}
_, err := fmt.Fprintf(outw, "%g;%g\n", n1, n2)
if err != nil {
fmt.Fprint(os.Stderr, err)
return
}
}
}
Playground: https://play.golang.org/p/I_sT_EPFI_W
Output:
$ go run data.go
$ cat in1.data
-0,1296169 -0,1286087 -0,1276232
-0,1288124 -0,1278683 -0,1269373
-0,1280221 -0,1271375 -0,12626
$ cat in2.data
-0,1296169 -0,1286087 -0,1276232
-0,1288124 -0,1278683 -0,1269373
-0,1280221 -0,1271375 -0,12626
$ cat out.data
-0.1296169;-0.1296169
-0.1286087;-0.1286087
-0.1276232;-0.1276232
-0.1288124;-0.1288124
-0.1278683;-0.1278683
-0.1269373;-0.1269373
-0.1280221;-0.1280221
-0.1271375;-0.1271375
-0.12626;-0.12626
$

Something like this. Note the limitation that assumes same number of values per line. Be careful it would blowup with the error if this assumption is wrong :)
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
file_dB, err := os.Open("dB.txt")
if err != nil {
fmt.Printf("error opening file: %v\n", err)
return
}
defer file_dB.Close()
file_dL, err := os.Open("dL.txt")
if err != nil {
fmt.Printf("error opening file: %v\n", err)
return
}
defer file_dL.Close()
file_out, err := os.Create("out.txt") // also rewrite existing !
if err != nil {
fmt.Printf("error opening file: %v\n", err)
return
}
defer file_out.Close()
dB := bufio.NewReader(file_dB)
dL := bufio.NewReader(file_dL)
lc := 0
for {
lc++
line1, _, err := dB.ReadLine()
vals1 := strings.Split(string(line1), " ")
if err != nil {
fmt.Println(lc, err)
return
}
line2, _, err := dL.ReadLine()
vals2 := strings.Split(string(line2), " ")
if err != nil {
fmt.Println(lc, err)
return
}
// Limitation: assumes line1 and line2 have same number of values per line
for i := range vals1 {
dot1 := strings.Replace(vals1[i], ",", ".", 1)
v1, err := strconv.ParseFloat(dot1, 64)
if err != nil {
fmt.Println(lc, err)
continue
}
dot2 := strings.Replace(vals2[i], ",", ".", 1)
v2, err := strconv.ParseFloat(dot2, 64)
if err != nil {
fmt.Println(lc, err)
continue
}
_, err = fmt.Fprintf(file_out, "%v; %v\n", v1, v2)
if err != nil {
fmt.Println(lc, err)
return
}
}
}
}

Related

How to check if a QLDB result is empty using Go?

In Go, how can I check if a AWS QLDB result is empty?
In node, the following would do the trick:
txn.execute(statement).then((result: Result) => {
const resultList: dom.Value[] = result.getResultList();
if (resultList.length === 0) {
// DO something
}
)}
I've been reading the official quick start, but examples "assumes the results are not empty":
p, err := driver.Execute(context.Background(), func(txn qldbdriver.Transaction) (interface{}, error) {
result, err := txn.Execute("SELECT firstName, lastName, age FROM People WHERE age = 54")
if err != nil {
return nil, err
}
// Assume the result is not empty
hasNext := result.Next(txn)
if !hasNext && result.Err() != nil {
return nil, result.Err()
}
ionBinary := result.GetCurrentData()
temp := new(Person)
err = ion.Unmarshal(ionBinary, temp)
if err != nil {
return nil, err
}
return *temp, nil
})

Golang FormFile unit test

I have the following function:
func CreateByID(w http.ResponseWriter, r *http.Request) {
formFile, _, err := r.FormFile("audio")
if err != nil {
return
}
defer formFile.Close()
defer r.MultipartForm.RemoveAll()
tmpFile, err := os.CreateTemp("/tmp")
if err != nil {
return
}
defer os.Remove(tmpFile.Name())
io.Copy(tmpFile, formFile)
err = validateFile(tmpFile.Name())
if err != nil {
return
}
}
func validateFile(path string) error {
fs, err := os.Stat(path)
if err != nil {
return
}
if fs.Size() < allowedSize {
return fmt.Errorf("file is too small")
}
}
which is basically creating a temp file from the HTTP request and validating it before further processing. This works fine except for the unit test. When I'm testing this function - I'm getting always filesize = 0.
Below you can see the Test case:
func TestCreateByID(t *testing.T) {
pr, pw := io.Pipe()
writer := multipart.NewWriter(pw)
go func() {
defer writer.Close()
_, err := writer.CreateFormFile("audio", "/tmp/audioFile")
if err != nil {
t.Error(err)
}
generateAudioSample("/tmp/audioFile")
}()
request := httptest.NewRequest(http.MethodGet, "/{id}")
request.Header.Add("Content-Type", writer.FormDataContentType())
response := httptest.NewRecorder()
# Calling The Actual Function
CreateByID(response, request)
handler := http.NewServeMux()
handler.ServeHTTP(response, request)
if response.Code != 200 {
t.Errorf("Expected %d, received %d", 200, response.Code)
return
}
}
generateAudioSample function is working fine because I can see the file on the filesystem and its size it bigger than 0 but for some reason this function io.Copy(tmpFile, formFile) doesn't seem to handle FormFile correctly, and is creating just an empty file on the filesystem and obviously fail the test. What else should I add to the test function in order to pass the test?

Test TCP connection timeout - net.Listener.Accept() hangs

I'm trying to test a function that tries to establish a TCP connection.
I'm trying to run a test case that should return an error indicating that a certain IP is not reachable.
The code fails if I wait for a certain amount of time, bigger than the timeout specified, or if I try to connect to a port that wouldn't be available.
The failure seems to be in l.Accept() in the tests. The code does not run after that.
The code:
func Run(
trackerInfo tracker.NotCompactGetRequestResponse,
infoHash [20]byte,
) (err error) {
for _, peer := range trackerInfo.Peers {
conn, err := peerTcpConnection(peer.Ip, peer.Port)
if err != nil {
return PeerConnectionError{
Reason: err.Error(),
}
}
defer conn.Close()
handshake := Handshake{
Pstr: "BitTorrent protocol",
InfoHash: infoHash,
PeerId: [20]byte(tracker.GetPeerIdAsByteArray()),
}
serializedHandshake, err := handshake.Serialize()
if err != nil {
return err
}
_, err = conn.Write(serializedHandshake)
if err != nil {
return err
}
}
return nil
}
func peerTcpConnection(url, port string) (conn net.Conn, err error) {
address := fmt.Sprintf("%v:%v", url, port)
return net.DialTimeout("tcp", address, peerTimeout) // 3 * time.Second
}
The test:
func TestRun(t *testing.T) {
// t.Parallel()
testCases := getTestCases()
for _, testCase := range testCases {
testCase := testCase
t.Run(testCase.name, func(t *testing.T) {
// t.Parallel()
errChannel := make(chan error)
go func() {
fmt.Println(fmt.Sprintf("1 -> %v", time.Now()))
errChannel <- download.Run(testCase.trackerInfo, testCase.infoHash)
fmt.Println(fmt.Sprintf("2 -> %v", time.Now()))
}()
l, conn := getTestConnection(t, testCase.trackerInfo.Peers[0].Port)
defer func() {
err := conn.Close()
if err != nil {
t.Fatal(err)
}
err = l.Close()
if err != nil {
t.Fatal(err)
}
}()
err := <-errChannel
if !errors.Is(err, testCase.expectedErr) {
t.Errorf(
"got error '%v', expected error '%v'",
err,
testCase.expectedErr,
)
}
var buffer []byte
buffer, err = ioutil.ReadAll(conn)
if err != nil {
t.Fatal(err)
}
receivedHandshake := download.Handshake{}
receivedHandshake.Deserialize(buffer)
if !download.CompareHandshakes(receivedHandshake, testCase.expectedHandshake) {
t.Errorf(
"got handshake '%v', expected handshake '%v'",
err,
testCase.expectedHandshake,
)
}
})
}
}
func getTestConnection(t *testing.T, port string) (l net.Listener, conn net.Conn) {
if port == "34568" {
// portN, err := strconv.Atoi(port)
// if err != nil {
// t.Fatal(err)
// }
// port = fmt.Sprint(portN + 1)
time.Sleep(4 * time.Second)
}
l, err := net.Listen("tcp", fmt.Sprintf(":%v", port))
if err != nil {
t.Fatal(err)
}
fmt.Println(fmt.Sprintf("3 -> %v", time.Now()))
conn, err = l.Accept()
fmt.Println(fmt.Sprintf("4 -> %v", time.Now()))
if err != nil {
t.Fatal(err)
}
return l, conn
}
The result:
=== RUN TestRun
=== RUN TestRun/successful_download
1 -> 2022-03-16 15:31:04.542987703 +0000 UTC m=+0.000510682
3 -> 2022-03-16 15:31:04.543043416 +0000 UTC m=+0.000566399
4 -> 2022-03-16 15:31:04.543208564 +0000 UTC m=+0.000731539
2 -> 2022-03-16 15:31:04.543257141 +0000 UTC m=+0.000780117
=== RUN TestRun/unsuccessful_download_-_cannot_connect_to_peer
1 -> 2022-03-16 15:31:04.543331399 +0000 UTC m=+0.000854375
3 -> 2022-03-16 15:31:08.543806112 +0000 UTC m=+4.001329160

Insert a slice of items in DynamoDB

Is it possible to insert a slice of struct (item) into dynamoDB? Currently, I can only insert one item. Here is how my current function does this.
func Insert(doc interface{}) error {
av, err := dynamodbattribute.MarshalMap(doc)
if err != nil {
return err
}
input := &dynamodb.PutItemInput{
Item: av,
TableName: "schools",
}
_, err = svc.PutItem(input)
if err != nil {
return err
}
return nil
}
How do I adjust the Insert function to insert a slice of items?
func InsertMulti(doc []interface{}) error { - what should be here?
Here is what I have been able to do
func InsertMulti (doc []interface{}) error {
for _, v := range doc {
av, err := dynamodbattribute.MarshalMap(doc)
if err != nil {
return err
}
}
input := &dynamodb.BatchWriteItemInput{
RequestItems: map[string][]*dynamodb.WriteRequest{
"schools" : {
}
}
}
}

Golang Escape Question Mark Character for Cisco Regex

So, Cisco's regex allows the question mark character. But the catch is that you have to precede typing a question mark with Ctrl-Shift-v in order for it to be interpreted as a question mark and not a help command... Link to Cisco regex guidelines
I have a Go program that logs into a set of devices and runs a set of commands on each device. When trying to use a regex containing a question mark, though, the Cisco device always interprets the question mark as a help command. Using string literals in Go does not fix the problem nor does sending the command as a slice of bytes.
For example, if I try to send the command show boot | include (c|cat)[0-9]+[a-zA-Z]? the Cisco CLI returns
switch-1#show boot | include (c|cat)[0-9]+[a-zA-Z]?
LINE <cr>
switch-1#
instead of interpreting the question mark as a regex match of 0 or 1 for the [a-zA-Z] group.
However, using the command ssh user#switch-1 'show boot | include (c|cat)[0-9]+[a-zA-Z]?' works as expected and interprets the regex pattern correctly.
How can I replicate the behaviour of the ssh command? Is there a way to send Ctrl-Shift-v before each question mark or escape each question mark character?
My code as requested:
package main
import (
"golang.org/x/crypto/ssh"
"net"
"fmt"
"os"
"bufio"
"time"
"golang.org/x/crypto/ssh/terminal"
"io"
"io/ioutil"
"sync"
"strings"
)
// ReadLines reads a file line-by-line and returns a slice of the lines.
func ReadLines(filename string) ([]string, error) {
f, err := os.Open(filename)
if err != nil {
return nil, fmt.Errorf("failed to open file: %v", err)
}
defer f.Close()
var lines []string
s := bufio.NewScanner(f)
for s.Scan() {
lines = append(lines, s.Text())
}
if err := s.Err(); err != nil {
return nil, err
}
return lines, nil
}
// Type Result represents the result of running the Configure method.
type Result struct {
Host string // Hostname of device
Output []byte // Remote shell's stdin and stderr output
Err error // Remote shell errors
}
// Configure logs into a device, starts a remote shell, runs the set of
// commands, and waits for the remote shell to return or timeout.
func Configure(host string, config *ssh.ClientConfig, cmds []string, results chan<- *Result, wg *sync.WaitGroup) {
defer wg.Done()
res := &Result{
Host: host,
Output: nil,
Err: nil,
}
// Create client connection
client, err := ssh.Dial("tcp", net.JoinHostPort(host, "22"), config)
if err != nil {
res.Err = fmt.Errorf("failed to dial: %v", err)
results <- res
return
}
defer client.Close()
// Create new session
session, err := client.NewSession()
if err != nil {
res.Err = fmt.Errorf("failed to create session: %v", err)
results <- res
return
}
defer session.Close()
// Set session IO
stdin, err := session.StdinPipe()
if err != nil {
res.Err = fmt.Errorf("failed to create pipe to stdin: %v", err)
results <- res
return
}
defer stdin.Close()
stdout, err := session.StdoutPipe()
if err != nil {
res.Err = fmt.Errorf("failed to create pipe to stdout: %v", err)
results <- res
return
}
stderr, err := session.StderrPipe()
if err != nil {
res.Err = fmt.Errorf("failed to create pipe to stderr: %v", err)
results <- res
return
}
// Start remote shell
if err := session.RequestPty("vt100", 0, 0, ssh.TerminalModes{
ssh.ECHO: 0,
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400,
}); err != nil {
res.Err = fmt.Errorf("failed to request pseudoterminal: %v", err)
results <- res
return
}
if err := session.Shell(); err != nil {
res.Err = fmt.Errorf("failed to start remote shell: %v", err)
results <- res
return
}
// Run commands
for _, cmd := range cmds {
if _, err := io.WriteString(stdin, cmd+"\n"); err != nil {
res.Err = fmt.Errorf("failed to run: %v", err)
results <- res
return
}
}
// Wait for remote commands to return or timeout
exit := make(chan error, 1)
go func(exit chan<- error) {
exit <- session.Wait()
}(exit)
timeout := time.After(1 * time.Minute)
select {
case <-exit:
output, err := ioutil.ReadAll(io.MultiReader(stdout, stderr))
if err != nil {
res.Err = fmt.Errorf("failed to read output: %v", err)
results <- res
return
}
res.Output = output
results <- res
return
case <-timeout:
res.Err = fmt.Errorf("session timed out")
results <- res
return
}
}
func main() {
hosts, err := ReadLines(os.Args[1])
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
cmds, err := ReadLines(os.Args[2])
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
fmt.Fprint(os.Stderr, "Password: ")
secret, err := terminal.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
fmt.Fprintf(os.Stderr, "failed to read password: %v\n", err)
os.Exit(1)
}
fmt.Fprintln(os.Stderr)
config := &ssh.ClientConfig{
User: "user",
Auth: []ssh.AuthMethod{ssh.Password(string(secret))},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Timeout: 30 * time.Second,
}
config.SetDefaults()
config.Ciphers = append(config.Ciphers, "aes128-cbc", "3des-cbc", "aes192-cbc", "aes256-cbc")
results := make(chan *Result, len(hosts))
var wg sync.WaitGroup
wg.Add(len(hosts))
for _, host := range hosts {
go Configure(host, config, cmds, results, &wg)
}
wg.Wait()
close(results)
for res := range results {
if res.Err != nil {
fmt.Fprintf(os.Stderr, "Error %s: %v\n", res.Host, res.Err)
continue
}
fmt.Printf("Host %s\n%s\n%s\n", res.Host, res.Output, strings.Repeat("-", 50))
}
}
Try forcing the IOS terminal server into line mode (as opposed to character mode). Send these telnet negotiation sequences:
IAC DONT ECHO
IAC WONT ECHO
IAC DONT SUPPRESS-GO-AHEAD
IAC WONT SUPPRESS-GO-AHEAD
See: https://www.rfc-editor.org/rfc/rfc858