Bash Process Substitution with WSL - bash

I am trying to understand the following (odd?) behavior on my setup. I am running Windows 10, with WSL.
Here is what I see from my powershell+wsl session:
$ ./run.sh
Windows IP Configuration
<cut>
1
with:
$ cat run.sh
#!/bin/bash
mkdir -p dir/1
mkdir -p dir/2
mkdir -p dir/3
var=0
while read i;
do
((var++))
ipconfig.exe
done < <(find dir -type d)
echo $var
If I now comment out the ipconfig.exe line:
...
#ipconfig.exe
...
Here is now what I get:
$ ./run.sh
4
Why calling a window executable (eg. ipconfig.exe) seems to interfere with my while loop using process substitution) ?
For reference:
$ uname -a
Linux FR-L0002146 5.10.102.1-microsoft-standard-WSL2 #1 SMP Wed Mar 2 00:30:59 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
and
$ bash -version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Most likely ipconfig.exe is reading from stdin, so it's sucking up the input from the process substitution. Redirect its input to /dev/null to prevent this.
while read i;
do
((var++))
ipconfig.exe </dev/null
done < <(find dir -type d)

Related

why mv command in verbose mode prints 'renamed' instead of 'moved' when moving file with specific directory location with -t option?

For Example to simulate the issue, execute following in linux (CentOS 7)
## create temporary destination directory
mkdir -p /tmp/b/
## create temporary file to move to destination directory
touch /tmp/a.txt
## execute move
mv -v /tmp/a.txt -t /tmp/b/
renamed '/tmp/a.txt' -> '/tmp/b/a.txt'
As you can see above the verbose output says "renamed" instead of moved, is there any way we can make it print to moved (without piping and replacing words using sed/awk)
$ /bin/mv --version
mv (GNU coreutils) 8.22
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Mike Parker, David MacKenzie, and Jim Meyering.
mvuses the underlying rename system command. Hence it's logical that the mv action reports a 'rename' event.

Stale file descriptor with /dev/stdin

I'm attempting to write a script to loop over entries in .ssh/authorized_keys and do things with them, namely print their fingerprint and append them to a new place. This is what I have so far:
echo "$SSH_KEYS" | while read key ; do
ssh-keygen -lf /dev/stdin <<< "$key"
echo "$key" >> newplace
done
This unfortunately gives me the following error:
/dev/stdin: Stale file handle
I'm running Bash 4.3.11 on Ubuntu 14.04 kernel 3.13.0-24-generic.
On the same kernel running Bash 4.3.8, it works fine. Changing my version of Bash doesn't look to be an option at this point, this is an automated script for something in production.
I found this solution in another question here on StackOverflow but it seems to not work with this later version of Bash.
I think you're on the right track, but you want something like:
while read key; do
ssh-keygen -lf /dev/stdin <<< "$key"
echo "$key" >> newplace
done < .ssh/authorized_keys
As opposed to:
echo "$SSH_KEYS" | while read key ; do
ssh-keygen -lf /dev/stdin <<< "$key"
echo "$key" >> newplace
done
Note that instead of piping the output of echo, simply feed the file directly into the stdin of the while loop.
This worked for me on:
$ bash --version
GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
I'm also on Ubuntu 14.04, but it seems that someone has also maybe seen this problem: https://github.com/docker/docker/issues/2067
A work-around is to write each key to a tempfile, process it, then remove the file.

Making new sub-directories using curly brace expansion

Given two directories; dira and dirb, how can I make subdirectories using curly brace expansion in mkdir command?
For instance, I have tried: mkdir -p {dira, dirb}/sub. This results in two new directories called {dira, and dirb}. Instead, I would like instead to have dira/sub and dirb/sub.
I am running the following version:
GNU bash, version 3.2.51(1)-release (x86_64-apple-darwin13)
Copyright (C) 2007 Free Software Foundation, Inc.
Try:
$ mkdir -p {dira,dirb}/sub
$ find .
.
./dirb
./dirb/sub
./dira
./dira/sub
Using GNU bash, version 4.2.37(1)-release (x86_64-pc-linux-gnu)

lowercase or rename all files in a directory on Mac OS X

After putting hours into this, I give up, and am asking for help. This has been answered perfectly in a previous SO question here: How do I rename all files to lowercase?
The trouble is, it does not work on Mac OS X. So I went about working to redo it so it would work. Learned a little about strong/weak quoting, which I thought had something to do with it. For now, I am using strong quoting on everything.
#!/bin/bash
echo ""; echo "Start run `basename $0` on `date`";
echo "Script running from: `pwd`";
# Change into the directory with the files to rename
cd /Users/me/Desktop/files
echo "Working on files in: `pwd`"; echo "";
# Read in all files from a directory
for file in *; do
lowercase_filename=`echo $file | tr '[:upper:]' '[:lower:]'`;
echo \'$file\' \'$lowercase_filename\';
mv \'$file\' \'$lowercase_filename\';
echo "--------------------";
done
Here is what the above script will output when run:
./renamer.sh
Start run renamer.sh on Fri Nov 25 04:35:00 PST 2011
Script running from: /Users/me/Desktop
Working on files in: /Users/me/Desktop/files
'This IS A test TEST.txt' 'this is a test test.txt'
usage: mv [-f | -i | -n] [-v] source target
mv [-f | -i | -n] [-v] source ... directory
For some reason, mv doesn't work. However, what is strange, is if I take the debugging output and manually run this, it will work fine. So I have a before and and after string of a filename, in this case, the before is the mixed case and the after is the lowercase. The strings are quoted in single tic marks. I echo them out just as I would pass them as two args to the mv command.
'This IS A test TEST.txt' 'this is a test test.txt'
The script gives me an error, but if I run these commands by hand:
# "l" is an alias for ls with some args to remove fot files
# and other junk I don't want to see.
me#whitebook:\ $cd files
me#whitebook:\ $l
-rw-r--r--+ 1 me staff 0 Nov 25 03:49 This IS A test TEST.txt
me#whitebook:\ $mv 'This IS A test TEST.txt' 'this is a test test.txt'
me#whitebook:\ $l
-rw-r--r--+ 1 me staff 0 Nov 25 03:49 this is a test test.txt
As you can see the file was renamed with lowercase just fine to "this is a test test.txt". If I can mv these by hand, then something is happening inside the scripts environment that is getting it confused. Any idea what that may be?
I should be able to one-line this as the other poster has done, but no matter what I try, it doesn't work for me.
Thanks for any guidance. I am on Mac OS X, here is some relevant system info...
$uname -a
Darwin whitebook.local 11.2.0 Darwin Kernel Version 11.2.0: Tue Aug 9 20:56:15 PDT 2011; root:xnu-1699.24.8~1/RELEASE_I386 i386
$bash --version
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11)
Copyright (C) 2007 Free Software Foundation, Inc.
Can you try this?
mv "$file" "$lowercase_filename";

How to check the ls version

This topic is about the util 'ls'
The BSD version uses the parameter '-G' to color up the output,
while the Linux version uses parameter '--color'
Also the environment variable to set the colors is different:
BSD: $LSCOLORS
Linux: $LS_COLORS
But now the problem is: I want to determine which version is installed (using a small Shell script), so I can set alias ls and the environment appropriate in my .bachrc file.
As I mentioned above this seems to me to be the handiest method
if ls --color -d . >/dev/null 2>&1; then
GNU_LS=1
elif ls -G -d . >/dev/null 2>&1; then
BSD_LS=1
else
SOLARIS_LS=1
fi
I've essentially this in my l script, which I use on various platforms to tweak ls output as I like
Just run 'ls' and see whether it throws an error, e.g. on my mac:
$ ls --color 1>/dev/null 2>&1
$ echo $?
1
Whereas
$ ls -G 1>/dev/null 2>&1
$ echo $?
0
Indicating -G is supported, but --color is not.
Ironically, the --version switch Kimmo mentions is not supported on most BSD systems :-)
Writing a portable configuration file for your particular setup can be a Herculean task. In your case, if you're sure your .bashrc is going to be used only on GNU/Linux and on a BSD system, you can check for switches that exist in one of the ls' but not in the other: for example, -D doesn't seem to be an accepted switch by ls on my BSD machines (FreeBSD and Mac OS X), whereas it is for GNU ls. Conversely, -P is accepted on BSD, but not on GNU/Linux. Knowing this, you can distinguish between the two ls' and set up environment variables accordingly.
$ ls --version
ls (GNU coreutils) 6.10
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Richard Stallman and David MacKenzie.
combining the methods described, here's an easy way to use a bash function instead of an alias in order to make colors work regardless of if you are using BSD or GNU ls.
ll () {
if ls --version &>/dev/null; then
ls --color=auto -lahtr
else
ls -Glahtr
fi
}
inspired by a particular conda env recipe pulling in GNU ls on my macOS system where my ls aliases were all hard-coded for stock BSD ls only.

Resources